summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhar7an <99636919+har7an@users.noreply.github.com>2022-09-09 13:21:03 +0000
committerGitHub <noreply@github.com>2022-09-09 13:21:03 +0000
commit99e2bef8c68bd166cf89e90c8ffe8c02272ab4d3 (patch)
tree1eb34d081e8d96c9f6d49f26beb8e0d97666aa6e
parent3f43a057cb65e5790f8024fe0d961255f6699678 (diff)
Feature: Better error handling/reporting (#1670)
* utils: re-export "anyhow" unconditionally even for wasm targets. * utils/errors: Share wasm-compatible code and move everything that can't run in wasm into a separate submodule. * utils: Share "errors" module unconditionally The module is now structured such that all code incompatible with wasm targets lives in its own submodule that isn't included when compiling for wasm targets. * utils/errors: Add "Help wanted" doc section that informs the reader about the endeavour to improve error handling throughout the zellij code base. * plugins: Handle errors returned by `zellij_tile` now that the panic calls have been removed. * utils/errors: Extend `anyhow::Result` with traits that allow for easy/concise logging of `anyhow::Result` types and panicking the application when they are fatal or non-fatal. * utils/errors: Fix doctest * utils/errors: Add prelude that applications can import to conveniently access the error handling functionality part of the module. Re-exports some parts and macros from anyhow and the `LoggableError` and `FatalError` traits. * server/screen: Adopt error handling and make all fallible functions from the public API return a `Result`. Append error contexts in all functions that can come across error types to allow tracing where an error originates and what lead there. * server/lib: Catch errors from `screen` and make them `fatal`. This will log the errors first, before unwrapping on the error type and panicking the application. * server/unit/screen: Fix unit tests and unwrap on the `Result` types introduced from the new error handling. * utils/errors: Track error source in calls to `fatal`, so we keep track of the location where the panic really originates. Otherwise, any call to `fatal` will show the code in `errors` as source, which of course isn't true. Also change the error formatting and do not call `to_log` for fatal errors anymore, because the panic is already logged and contains much more information. * utils/errors: Update `FatalError` docs * plugins: Undo accidental modifications * utils/errors: Improve module docs explain some error handling facilities and the motivation behind using them. * server/screen: Remove `Result` from Infallible functions that are part of the public API.
-rw-r--r--zellij-server/src/lib.rs5
-rw-r--r--zellij-server/src/screen.rs396
-rw-r--r--zellij-server/src/unit/screen_tests.rs66
-rw-r--r--zellij-utils/src/errors.rs447
-rw-r--r--zellij-utils/src/lib.rs9
5 files changed, 602 insertions, 321 deletions
diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs
index 400026b15..b3f17ad33 100644
--- a/zellij-server/src/lib.rs
+++ b/zellij-server/src/lib.rs
@@ -40,7 +40,7 @@ use zellij_utils::{
cli::CliArgs,
consts::{DEFAULT_SCROLL_BUFFER_SIZE, SCROLL_BUFFER_SIZE},
data::{Event, PluginCapabilities},
- errors::{ContextType, ErrorInstruction, ServerContext},
+ errors::{ContextType, ErrorInstruction, FatalError, ServerContext},
input::{
command::{RunCommand, TerminalAction},
get_mode_info,
@@ -691,7 +691,8 @@ fn init_session(
max_panes,
client_attributes_clone,
config_options,
- );
+ )
+ .fatal();
}
})
.unwrap();
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index e3323b41e..b302db4be 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -6,6 +6,7 @@ use std::os::unix::io::RawFd;
use std::rc::Rc;
use std::str;
+use zellij_utils::errors::prelude::*;
use zellij_utils::input::options::Clipboard;
use zellij_utils::pane_size::{Size, SizeInPixels};
use zellij_utils::{input::command::TerminalAction, input::layout::Layout, position::Position};
@@ -419,13 +420,20 @@ impl Screen {
},
}
}
+
/// A helper function to switch to a new tab at specified position.
- fn switch_active_tab(&mut self, new_tab_pos: usize, client_id: ClientId) {
+ fn switch_active_tab(&mut self, new_tab_pos: usize, client_id: ClientId) -> Result<()> {
+ let err_context = || {
+ format!(
+ "Failed to switch to active tab at position {new_tab_pos} for client id: {client_id:?}"
+ )
+ };
+
if let Some(new_tab) = self.tabs.values().find(|t| t.position == new_tab_pos) {
if let Some(current_tab) = self.get_active_tab(client_id) {
// If new active tab is same as the current one, do nothing.
if current_tab.position == new_tab_pos {
- return;
+ return Ok(());
}
let current_tab_index = current_tab.index;
@@ -454,27 +462,29 @@ impl Screen {
log::error!("Tab index: {:?} not found", current_tab_index);
}
- self.update_tabs();
- self.render();
+ self.update_tabs().with_context(err_context)?;
+ return self.render().with_context(err_context);
} else {
- log::error!("Active tab not found for client_id: {:?}", client_id);
+ log::error!("Active tab not found for client id: {client_id:?}");
}
}
+ Ok(())
}
/// Sets this [`Screen`]'s active [`Tab`] to the next tab.
- pub fn switch_tab_next(&mut self, client_id: ClientId) {
+ pub fn switch_tab_next(&mut self, client_id: ClientId) -> Result<()> {
if let Some(active_tab) = self.get_active_tab(client_id) {
let active_tab_pos = active_tab.position;
let new_tab_pos = (active_tab_pos + 1) % self.tabs.len();
- self.switch_active_tab(new_tab_pos, client_id);
+ self.switch_active_tab(new_tab_pos, client_id)
} else {
- log::error!("Active tab not found for client_id: {:?}", client_id);
+ log::error!("Active tab not found for client id: {client_id:?}");
+ Ok(())
}
}
/// Sets this [`Screen`]'s active [`Tab`] to the previous tab.
- pub fn switch_tab_prev(&mut self, client_id: ClientId) {
+ pub fn switch_tab_prev(&mut self, client_id: ClientId) -> Result<()> {
if let Some(active_tab) = self.get_active_tab(client_id) {
let active_tab_pos = active_tab.position;
let new_tab_pos = if active_tab_pos == 0 {
@@ -483,18 +493,20 @@ impl Screen {
active_tab_pos - 1
};
- self.switch_active_tab(new_tab_pos, client_id);
+ self.switch_active_tab(new_tab_pos, client_id)
} else {
- log::error!("Active tab not found for client_id: {:?}", client_id);
+ log::error!("Active tab not found for client id: {client_id:?}");
+ Ok(())
}
}
- pub fn go_to_tab(&mut self, tab_index: usize, client_id: ClientId) {
- self.switch_active_tab(tab_index - 1, client_id);
+ pub fn go_to_tab(&mut self, tab_index: usize, client_id: ClientId) -> Result<()> {
+ self.switch_active_tab(tab_index - 1, client_id)
}
- fn close_tab_at_index(&mut self, tab_index: usize) {
- let mut tab_to_close = self.tabs.remove(&tab_index).unwrap();
+ fn close_tab_at_index(&mut self, tab_index: usize) -> Result<()> {
+ let err_context = || format!("failed to close tab at index {tab_index:?}");
+ let mut tab_to_close = self.tabs.remove(&tab_index).with_context(err_context)?;
let pane_ids = tab_to_close.get_all_pane_ids();
// 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
@@ -502,13 +514,13 @@ impl Screen {
self.bus
.senders
.send_to_pty(PtyInstruction::CloseTab(pane_ids))
- .unwrap();
+ .with_context(err_context)?;
if self.tabs.is_empty() {
self.active_tab_indices.clear();
self.bus
.senders
.send_to_server(ServerInstruction::Render(None))
- .unwrap();
+ .with_context(err_context)
} else {
let client_mode_infos_in_closed_tab = tab_to_close.drain_connected_clients(None);
self.move_clients_from_closed_tab(client_mode_infos_in_closed_tab);
@@ -523,25 +535,33 @@ impl Screen {
t.position -= 1;
}
}
- self.update_tabs();
- self.render();
+ self.update_tabs().with_context(err_context)?;
+ self.render().with_context(err_context)
}
}
// Closes the client_id's focused tab
- pub fn close_tab(&mut self, client_id: ClientId) {
- let active_tab_index = *self.active_tab_indices.get(&client_id).unwrap();
- self.close_tab_at_index(active_tab_index);
+ pub fn close_tab(&mut self, client_id: ClientId) -> Result<()> {
+ let err_context = || format!("failed to close tab for client {client_id:?}");
+
+ let active_tab_index = *self
+ .active_tab_indices
+ .get(&client_id)
+ .with_context(err_context)?;
+ self.close_tab_at_index(active_tab_index)
+ .with_context(err_context)
}
- pub fn resize_to_screen(&mut self, new_screen_size: Size) {
+ pub fn resize_to_screen(&mut self, new_screen_size: Size) -> Result<()> {
self.size = new_screen_size;
for tab in self.tabs.values_mut() {
tab.resize_whole_tab(new_screen_size);
tab.set_force_render();
}
- self.render();
+ self.render()
+ .context("failed to resize to screen size: {new_screen_size:#?}")
}
+
pub fn update_pixel_dimensions(&mut self, pixel_dimensions: PixelDimensions) {
self.pixel_dimensions.merge(pixel_dimensions);
if let Some(character_cell_size) = self.pixel_dimensions.character_cell_size {
@@ -556,6 +576,7 @@ impl Screen {
*self.character_cell_size.borrow_mut() = Some(character_cell_size);
}
}
+
pub fn update_terminal_background_color(&mut self, background_color_instruction: String) {
if let Some(AnsiCode::RgbCode((r, g, b))) =
xparse_color(background_color_instruction.as_bytes())
@@ -564,6 +585,7 @@ impl Screen {
self.terminal_emulator_colors.borrow_mut().bg = bg_palette_color;
}
}
+
pub fn update_terminal_foreground_color(&mut self, foreground_color_instruction: String) {
if let Some(AnsiCode::RgbCode((r, g, b))) =
xparse_color(foreground_color_instruction.as_bytes())
@@ -572,6 +594,7 @@ impl Screen {
self.terminal_emulator_colors.borrow_mut().fg = fg_palette_color;
}
}
+
pub fn update_terminal_color_registers(&mut self, color_registers: Vec<(usize, String)>) {
let mut terminal_emulator_color_codes = self.terminal_emulator_color_codes.borrow_mut();
for (color_register, color_sequence) in color_registers {
@@ -580,7 +603,9 @@ impl Screen {
}
/// Renders this [`Screen`], which amounts to rendering its active [`Tab`].
- pub fn render(&mut self) {
+ pub fn render(&mut self) -> Result<()> {
+ let err_context = || "failed to render screen".to_string();
+
let mut output = Output::new(
self.sixel_image_store.clone(),
self.character_cell_size.clone(),
@@ -597,13 +622,14 @@ impl Screen {
}
}
for tab_index in tabs_to_close {
- self.close_tab_at_index(tab_index);
+ self.close_tab_at_index(tab_index)
+ .with_context(err_context)?;
}
let serialized_output = output.serialize();
self.bus
.senders
.send_to_server(ServerInstruction::Render(Some(serialized_output)))
- .unwrap();
+ .with_context(err_context)
}
/// Returns a mutable reference to this [`Screen`]'s tabs.
@@ -621,11 +647,20 @@ impl Screen {
/// Returns an immutable reference to this [`Screen`]'s previous active [`Tab`].
/// Consumes the last entry in tab history.
- pub fn get_previous_tab(&mut self, client_id: ClientId) -> Option<&Tab> {
- match self.tab_history.get_mut(&client_id).unwrap().pop() {
- Some(tab) => self.tabs.get(&tab),
- None => None,
- }
+ pub fn get_previous_tab(&mut self, client_id: ClientId) -> Result<Option<&Tab>> {
+ Ok(
+ match self
+ .tab_history
+ .get_mut(&client_id)
+ .with_context(|| {
+ format!("failed to retrieve tab history for client {client_id:?}")
+ })?
+ .pop()
+ {
+ Some(tab) => self.tabs.get(&tab),
+ None => None,
+ },
+ )
}
/// Returns a mutable reference to this [`Screen`]'s active [`Tab`].
@@ -648,7 +683,14 @@ impl Screen {
/// Creates a new [`Tab`] in this [`Screen`], applying the specified [`Layout`]
/// and switching to it.
- pub fn new_tab(&mut self, layout: Layout, new_pids: Vec<RawFd>, client_id: ClientId) {
+ pub fn new_tab(
+ &mut self,
+ layout: Layout,
+ new_pids: Vec<RawFd>,
+ client_id: ClientId,
+ ) -> Result<()> {
+ let err_context = || format!("failed to create new tab for client {client_id:?}",);
+
let tab_index = self.get_new_tab_index();
let position = self.tabs.len();
let mut tab = Tab::new(
@@ -658,7 +700,11 @@ impl Screen {
self.size,
self.character_cell_size.clone(),
self.sixel_image_store.clone(),
- self.bus.os_input.as_ref().unwrap().clone(),
+ self.bus
+ .os_input
+ .as_ref()
+ .with_context(|| format!("failed to create new tab for client {client_id:?}"))?
+ .clone(),
self.bus.senders.clone(),
self.max_panes,
self.style,
@@ -699,14 +745,14 @@ impl Screen {
self.tabs.insert(tab_index, tab);
if !self.active_tab_indices.contains_key(&client_id) {
// this means this is a new client and we need to add it to our state properly
- self.add_client(client_id);
+ self.add_client(client_id).with_context(err_context)?;
}
- self.update_tabs();
+ self.update_tabs().with_context(err_context)?;
- self.render();
+ self.render().with_context(err_context)
}
- pub fn add_client(&mut self, client_id: ClientId) {
+ pub fn add_client(&mut self, client_id: ClientId) -> Result<()> {
let mut tab_history = vec![];
if let Some((_first_client, first_tab_history)) = self.tab_history.iter().next() {
tab_history = first_tab_history.clone();
@@ -729,10 +775,12 @@ impl Screen {
self.tab_history.insert(client_id, tab_history);
self.tabs
.get_mut(&tab_index)
- .unwrap_or_else(|| panic!("Failed to attach client to tab with index {tab_index}"))
+ .with_context(|| format!("Failed to attach client to tab with index {tab_index}"))?
.add_client(client_id, None);
+ Ok(())
}
- pub fn remove_client(&mut self, client_id: ClientId) {
+
+ pub fn remove_client(&mut self, client_id: ClientId) -> Result<()> {
self.tabs.iter_mut().for_each(|(_, tab)| {
tab.remove_client(client_id);
if tab.has_no_connected_clients() {
@@ -746,10 +794,11 @@ impl Screen {
self.tab_history.remove(&client_id);
}
self.connected_clients.borrow_mut().remove(&client_id);
- self.update_tabs();
+ self.update_tabs()
+ .with_context(|| format!("failed to remote client {client_id:?}"))
}
- pub fn update_tabs(&self) {
+ pub fn update_tabs(&self) -> Result<()> {
for (client_id, active_tab_index) in self.active_tab_indices.iter() {
let mut tab_data = vec![];
for tab in self.tabs.values() {
@@ -783,11 +832,17 @@ impl Screen {
Some(*client_id),
Event::TabUpdate(tab_data),
))
- .unwrap();
+ .or_else(|err| {
+ let (_, error_context) = err.0;
+ Err(anyhow!("failed to send data to plugins"))
+ .context(error_context)
+ .context("failed to update tabs")
+ })?;
}
+ Ok(())
}
- pub fn update_active_tab_name(&mut self, buf: Vec<u8>, client_id: ClientId) {
+ pub fn update_active_tab_name(&mut self, buf: Vec<u8>, client_id: ClientId) -> Result<()> {
let s = str::from_utf8(&buf).unwrap();
if let Some(active_tab) = self.get_active_tab_mut(client_id) {
match s {
@@ -805,21 +860,28 @@ impl Screen {
}
},
}
- self.update_tabs();
+ self.update_tabs()
+ .context("failed to update active tabs name for client id: {client_id:?}")
} else {
- log::error!("Active tab not found for client id: {:?}", client_id);
+ log::error!("Active tab not found for client id: {client_id:?}");
+ Ok(())
}
}
- pub fn undo_active_rename_tab(&mut self, client_id: ClientId) {
+
+ pub fn undo_active_rename_tab(&mut self, client_id: ClientId) -> Result<()> {
if let Some(active_tab) = self.get_active_tab_mut(client_id) {
if active_tab.name != active_tab.prev_name {
active_tab.name = active_tab.prev_name.clone();
- self.update_tabs();
+ self.update_tabs()
+ .context("failed to undo renaming of active tab")?;
}
+ Ok(())
} else {
- log::error!("Active tab not found for client id: {:?}", client_id);
+ log::error!("Active tab not found for client id: {client_id:?}");
+ Ok(())
}
}
+
pub fn change_mode(&mut self, mode_info: ModeInfo, client_id: ClientId) {
let previous_mode = self
.mode_info
@@ -866,33 +928,41 @@ impl Screen {
tab.mark_active_pane_for_rerender(client_id);
}
}
- pub fn move_focus_left_or_previous_tab(&mut self, client_id: ClientId) {
+
+ pub fn move_focus_left_or_previous_tab(&mut self, client_id: ClientId) -> Result<()> {
if let Some(active_tab) = self.get_active_tab_mut(client_id) {
if !active_tab.move_focus_left(client_id) {
- self.switch_tab_prev(client_id);
+ self.switch_tab_prev(client_id)
+ .context("failed to move focus left")?;
}
} else {
log::error!("Active tab not found for client id: {:?}", client_id);
}
+ Ok(())
}
- pub fn move_focus_right_or_next_tab(&mut self, client_id: ClientId) {
+ pub fn move_focus_right_or_next_tab(&mut self, client_id: ClientId) -> Result<()> {
if let Some(active_tab) = self.get_active_tab_mut(client_id) {
if !active_tab.move_focus_right(client_id) {
- self.switch_tab_next(client_id);
+ self.switch_tab_next(client_id)
+ .context("failed to move focus right")?;
}
} else {
log::error!("Active tab not found for client id: {:?}", client_id);
}
+ Ok(())
}
- pub fn toggle_tab(&mut self, client_id: ClientId) {
- let tab = self.get_previous_tab(client_id);
+ pub fn toggle_tab(&mut self, client_id: ClientId) -> Result<()> {
+ let tab = self
+ .get_previous_tab(client_id)
+ .context("failed to toggle tabs")?;
if let Some(t) = tab {
let position = t.position;
- self.go_to_tab(position + 1, client_id);
+ self.go_to_tab(position + 1, client_id)
+ .context("failed to toggle tabs")?;
};
- self.update_tabs();
- self.render();
+ self.update_tabs().context("failed to toggle tabs")?;
+ self.render()
}
fn unblock_input(&self) {
@@ -911,7 +981,7 @@ pub(crate) fn screen_thread_main(
max_panes: Option<usize>,
client_attributes: ClientAttributes,
config_options: Box<Options>,
-) {
+) -> Result<()> {
// let mut scrollbacks: HashMap<String, PaneId> = HashMap::new();
let capabilities = config_options.simplified_ui;
let draw_pane_frames = config_options.pane_frames.unwrap_or(true);
@@ -942,7 +1012,8 @@ pub(crate) fn screen_thread_main(
let (event, mut err_ctx) = screen
.bus
.recv()
- .expect("failed to receive event on channel");
+ .context("failed to receive event on channel")
+ .fatal();
err_ctx.add_call(ContextType::Screen((&event).into()));
match event {
@@ -956,7 +1027,7 @@ pub(crate) fn screen_thread_main(
}
},
ScreenInstruction::Render => {
- screen.render();
+ screen.render()?;
},
ScreenInstruction::NewPane(pid, client_or_tab_index) => {
match client_or_tab_index {
@@ -973,45 +1044,45 @@ pub(crate) fn screen_thread_main(
},
};
screen.unblock_input();
- screen.update_tabs();
+ screen.update_tabs()?;
- screen.render();
+ screen.render()?;
},
ScreenInstruction::OpenInPlaceEditor(pid, client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.suppress_active_pane(pid, client_id));
screen.unblock_input();
- screen.update_tabs();
+ screen.update_tabs()?;
- screen.render();
+ screen.render()?;
},
ScreenInstruction::TogglePaneEmbedOrFloating(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.toggle_pane_embed_or_floating(client_id));
screen.unblock_input();
- screen.update_tabs(); // update tabs so that the ui indication will be send to the plugins
- screen.render();
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.render()?;
},
ScreenInstruction::ToggleFloatingPanes(client_id, default_shell) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.toggle_floating_panes(client_id, default_shell));
screen.unblock_input();
- screen.update_tabs(); // update tabs so that the ui indication will be send to the plugins
- screen.render();
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.render()?;
},
ScreenInstruction::HorizontalSplit(pid, client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.horizontal_split(pid, client_id));
screen.unblock_input();
- screen.update_tabs();
- screen.render();
+ screen.update_tabs()?;
+ screen.render()?;
},
ScreenInstruction::VerticalSplit(pid, client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.vertical_split(pid, client_id));
screen.unblock_input();
- screen.update_tabs();
- screen.render();
+ screen.update_tabs()?;
+ screen.render()?;
},
ScreenInstruction::WriteCharacter(bytes, client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| {
@@ -1024,166 +1095,166 @@ pub(crate) fn screen_thread_main(
ScreenInstruction::ResizeLeft(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.resize_left(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::ResizeRight(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.resize_right(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::ResizeDown(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.resize_down(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::ResizeUp(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab.resize_up(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::ResizeIncrease(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.resize_increase(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::ResizeDecrease(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.resize_decrease(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::SwitchFocus(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.focus_next_pane(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::FocusNextPane(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.focus_next_pane(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::FocusPreviousPane(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.focus_previous_pane(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::MoveFocusLeft(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.move_focus_left(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::MoveFocusLeftOrPreviousTab(client_id) => {
- screen.move_focus_left_or_previous_tab(client_id);
+ screen.move_focus_left_or_previous_tab(client_id)?;
screen.unblock_input();
- screen.render();
+ screen.render()?;
},
ScreenInstruction::MoveFocusDown(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.move_focus_down(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::MoveFocusRight(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.move_focus_right(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::MoveFocusRightOrNextTab(client_id) => {
- screen.move_focus_right_or_next_tab(client_id);
+ screen.move_focus_right_or_next_tab(client_id)?;
screen.unblock_input();
- screen.render();
+ screen.render()?;
},
ScreenInstruction::MoveFocusUp(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.move_focus_up(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::DumpScreen(file, client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.dump_active_terminal_screen(Some(file.to_string()), client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::EditScrollback(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.edit_scrollback(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::ScrollUp(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.scroll_active_terminal_up(client_id));
- screen.render();
+ screen.render()?;
},
ScreenInstruction::MovePane(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab