zellij/zellij-server/src/ui/pane_contents_and_ui.rs
Aram Drevekenin ca8438b0aa
feat(collaboration): implement multiple users (#957)
* work

* feat(collaboration): implement multiple users

* style(cleanup): some leftovers
2021-12-20 17:31:07 +01:00

189 lines
6.5 KiB
Rust

use crate::panes::PaneId;
use crate::tab::{Output, Pane};
use crate::ui::boundaries::Boundaries;
use crate::ui::pane_boundaries_frame::FrameParams;
use crate::ClientId;
use std::collections::HashMap;
use zellij_tile::data::{
client_id_to_colors, single_client_color, InputMode, Palette, PaletteColor,
};
pub struct PaneContentsAndUi<'a> {
pane: &'a mut Box<dyn Pane>,
output: &'a mut Output,
colors: Palette,
focused_clients: Vec<ClientId>,
multiple_users_exist_in_session: bool,
}
impl<'a> PaneContentsAndUi<'a> {
pub fn new(
pane: &'a mut Box<dyn Pane>,
output: &'a mut Output,
colors: Palette,
active_panes: &HashMap<ClientId, PaneId>,
multiple_users_exist_in_session: bool,
) -> Self {
let focused_clients: Vec<ClientId> = active_panes
.iter()
.filter(|(_c_id, p_id)| **p_id == pane.pid())
.map(|(c_id, _p_id)| *c_id)
.collect();
PaneContentsAndUi {
pane,
output,
colors,
focused_clients,
multiple_users_exist_in_session,
}
}
pub fn render_pane_contents_to_multiple_clients(
&mut self,
clients: impl Iterator<Item = ClientId>,
) {
if let Some(vte_output) = self.pane.render(None) {
// FIXME: Use Termion for cursor and style clearing?
self.output.push_str_to_multiple_clients(
&format!(
"\u{1b}[{};{}H\u{1b}[m{}",
self.pane.y() + 1,
self.pane.x() + 1,
vte_output
),
clients,
);
}
}
pub fn render_pane_contents_for_client(&mut self, client_id: ClientId) {
if let Some(vte_output) = self.pane.render(Some(client_id)) {
// FIXME: Use Termion for cursor and style clearing?
self.output.push_to_client(
client_id,
&format!(
"\u{1b}[{};{}H\u{1b}[m{}",
self.pane.y() + 1,
self.pane.x() + 1,
vte_output
),
);
}
}
pub fn render_fake_cursor_if_needed(&mut self, client_id: ClientId) {
let pane_focused_for_client_id = self.focused_clients.contains(&client_id);
let pane_focused_for_different_client = self
.focused_clients
.iter()
.filter(|&&c_id| c_id != client_id)
.count()
> 0;
if pane_focused_for_different_client && !pane_focused_for_client_id {
let fake_cursor_client_id = self
.focused_clients
.iter()
.find(|&&c_id| c_id != client_id)
.unwrap();
if let Some(colors) = client_id_to_colors(*fake_cursor_client_id, self.colors) {
if let Some(vte_output) = self.pane.render_fake_cursor(colors.0, colors.1) {
self.output.push_to_client(
client_id,
&format!(
"\u{1b}[{};{}H\u{1b}[m{}",
self.pane.y() + 1,
self.pane.x() + 1,
vte_output
),
);
}
}
}
}
pub fn render_pane_frame(
&mut self,
client_id: ClientId,
client_mode: InputMode,
session_is_mirrored: bool,
) {
let pane_focused_for_client_id = self.focused_clients.contains(&client_id);
let other_focused_clients: Vec<ClientId> = self
.focused_clients
.iter()
.filter(|&&c_id| c_id != client_id)
.copied()
.collect();
let pane_focused_for_differet_client = !other_focused_clients.is_empty();
let frame_color = self.frame_color(client_id, client_mode, session_is_mirrored);
let focused_client = if pane_focused_for_client_id {
Some(client_id)
} else if pane_focused_for_differet_client {
Some(*other_focused_clients.first().unwrap())
} else {
None
};
let frame_params = if session_is_mirrored {
FrameParams {
focused_client,
is_main_client: pane_focused_for_client_id,
other_focused_clients: vec![],
colors: self.colors,
color: frame_color,
other_cursors_exist_in_session: false,
}
} else {
FrameParams {
focused_client,
is_main_client: pane_focused_for_client_id,
other_focused_clients,
colors: self.colors,
color: frame_color,
other_cursors_exist_in_session: self.multiple_users_exist_in_session,
}
};
if let Some(vte_output) = self.pane.render_frame(client_id, frame_params, client_mode) {
// FIXME: Use Termion for cursor and style clearing?
self.output.push_to_client(
client_id,
&format!(
"\u{1b}[{};{}H\u{1b}[m{}",
self.pane.y() + 1,
self.pane.x() + 1,
vte_output
),
);
}
}
pub fn render_pane_boundaries(
&self,
client_id: ClientId,
client_mode: InputMode,
boundaries: &mut Boundaries,
session_is_mirrored: bool,
) {
let color = self.frame_color(client_id, client_mode, session_is_mirrored);
boundaries.add_rect(self.pane.as_ref(), color);
}
fn frame_color(
&self,
client_id: ClientId,
mode: InputMode,
session_is_mirrored: bool,
) -> Option<PaletteColor> {
let pane_focused_for_client_id = self.focused_clients.contains(&client_id);
if pane_focused_for_client_id {
match mode {
InputMode::Normal | InputMode::Locked => {
if session_is_mirrored || !self.multiple_users_exist_in_session {
let colors = single_client_color(self.colors); // mirrored sessions only have one focused color
Some(colors.0)
} else {
let colors = client_id_to_colors(client_id, self.colors);
colors.map(|colors| colors.0)
}
}
_ => Some(self.colors.orange),
}
} else {
None
}
}
}