Skip to content

Commit

Permalink
feat(terminals): send focus in/out events to terminal panes (#1908)
Browse files Browse the repository at this point in the history
* feat(terminals): send focus in/out events to terminal panes

* style(fmt): rustfmt

* style(fmt): rustfmt
  • Loading branch information
imsnif authored Nov 4, 2022
1 parent c34853a commit 8d1a497
Show file tree
Hide file tree
Showing 14 changed files with 480 additions and 55 deletions.
100 changes: 100 additions & 0 deletions zellij-server/src/panes/active_panes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use crate::tab::Pane;

use crate::{os_input_output::ServerOsApi, panes::PaneId, ClientId};
use std::collections::{BTreeMap, HashMap};

pub struct ActivePanes {
active_panes: HashMap<ClientId, PaneId>,
os_api: Box<dyn ServerOsApi>,
}

impl ActivePanes {
pub fn new(os_api: &Box<dyn ServerOsApi>) -> Self {
let os_api = os_api.clone();
ActivePanes {
active_panes: HashMap::new(),
os_api,
}
}
pub fn get(&self, client_id: &ClientId) -> Option<&PaneId> {
self.active_panes.get(client_id)
}
pub fn insert(
&mut self,
client_id: ClientId,
pane_id: PaneId,
panes: &mut BTreeMap<PaneId, Box<dyn Pane>>,
) {
self.unfocus_pane_for_client(client_id, panes);
self.active_panes.insert(client_id, pane_id);
self.focus_pane(pane_id, panes);
}
pub fn clear(&mut self, panes: &mut BTreeMap<PaneId, Box<dyn Pane>>) {
for pane_id in self.active_panes.values() {
self.unfocus_pane(*pane_id, panes);
}
self.active_panes.clear();
}
pub fn is_empty(&self) -> bool {
self.active_panes.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&ClientId, &PaneId)> {
self.active_panes.iter()
}
pub fn values(&self) -> impl Iterator<Item = &PaneId> {
self.active_panes.values()
}
pub fn remove(
&mut self,
client_id: &ClientId,
panes: &mut BTreeMap<PaneId, Box<dyn Pane>>,
) -> Option<PaneId> {
if let Some(pane_id_to_unfocus) = self.active_panes.get(&client_id) {
self.unfocus_pane(*pane_id_to_unfocus, panes);
}
self.active_panes.remove(client_id)
}
pub fn unfocus_all_panes(&self, panes: &mut BTreeMap<PaneId, Box<dyn Pane>>) {
for (_client_id, pane_id) in &self.active_panes {
self.unfocus_pane(*pane_id, panes);
}
}
pub fn focus_all_panes(&self, panes: &mut BTreeMap<PaneId, Box<dyn Pane>>) {
for (_client_id, pane_id) in &self.active_panes {
self.focus_pane(*pane_id, panes);
}
}
pub fn clone_active_panes(&self) -> HashMap<ClientId, PaneId> {
self.active_panes.clone()
}
pub fn contains_key(&self, client_id: &ClientId) -> bool {
self.active_panes.contains_key(client_id)
}
fn unfocus_pane_for_client(
&self,
client_id: ClientId,
panes: &mut BTreeMap<PaneId, Box<dyn Pane>>,
) {
if let Some(pane_id_to_unfocus) = self.active_panes.get(&client_id) {
self.unfocus_pane(*pane_id_to_unfocus, panes);
}
}
fn unfocus_pane(&self, pane_id: PaneId, panes: &mut BTreeMap<PaneId, Box<dyn Pane>>) {
if let PaneId::Terminal(terminal_id) = pane_id {
if let Some(focus_event) = panes.get(&pane_id).and_then(|p| p.unfocus_event()) {
let _ = self
.os_api
.write_to_tty_stdin(terminal_id, focus_event.as_bytes());
}
}
}
fn focus_pane(&self, pane_id: PaneId, panes: &mut BTreeMap<PaneId, Box<dyn Pane>>) {
if let PaneId::Terminal(terminal_id) = pane_id {
if let Some(focus_event) = panes.get(&pane_id).and_then(|p| p.focus_event()) {
let _ = self
.os_api
.write_to_tty_stdin(terminal_id, focus_event.as_bytes());
}
}
}
}
38 changes: 24 additions & 14 deletions zellij-server/src/panes/floating_panes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use floating_pane_grid::FloatingPaneGrid;
use crate::{
os_input_output::ServerOsApi,
output::{FloatingPanesStack, Output},
panes::PaneId,
panes::{ActivePanes, PaneId},
ui::pane_contents_and_ui::PaneContentsAndUi,
ClientId,
};
Expand Down Expand Up @@ -50,7 +50,7 @@ pub struct FloatingPanes {
session_is_mirrored: bool,
desired_pane_positions: HashMap<PaneId, PaneGeom>, // this represents the positions of panes the user moved with intention, rather than by resizing the terminal window
z_indices: Vec<PaneId>,
active_panes: HashMap<ClientId, PaneId>,
active_panes: ActivePanes,
show_panes: bool,
pane_being_moved_with_mouse: Option<(PaneId, Position)>,
}
Expand All @@ -67,6 +67,7 @@ impl FloatingPanes {
session_is_mirrored: bool,
default_mode_info: ModeInfo,
style: Style,
os_input: Box<dyn ServerOsApi>,
) -> Self {
FloatingPanes {
panes: BTreeMap::new(),
Expand All @@ -81,7 +82,7 @@ impl FloatingPanes {
desired_pane_positions: HashMap::new(),
z_indices: vec![],
show_panes: false,
active_panes: HashMap::new(),
active_panes: ActivePanes::new(&os_input),
pane_being_moved_with_mouse: None,
}
}
Expand Down Expand Up @@ -195,6 +196,11 @@ impl FloatingPanes {
}
pub fn toggle_show_panes(&mut self, should_show_floating_panes: bool) {
self.show_panes = should_show_floating_panes;
if should_show_floating_panes {
self.active_panes.focus_all_panes(&mut self.panes);
} else {
self.active_panes.unfocus_all_panes(&mut self.panes);
}
}
pub fn active_panes_contain(&self, client_id: &ClientId) -> bool {
self.active_panes.contains_key(client_id)
Expand Down Expand Up @@ -260,7 +266,7 @@ impl FloatingPanes {
});

for (z_index, (kind, pane)) in floating_panes.iter_mut().enumerate() {
let mut active_panes = self.active_panes.clone();
let mut active_panes = self.active_panes.clone_active_panes();
let multiple_users_exist_in_session =
{ self.connected_clients_in_app.borrow().len() > 1 };
active_panes.retain(|c_id, _| self.connected_clients.borrow().contains(c_id));
Expand Down Expand Up @@ -532,7 +538,7 @@ impl FloatingPanes {
},
None => {
// TODO: can this happen?
self.active_panes.clear();
self.active_panes.clear(&mut self.panes);
self.z_indices.clear();
},
}
Expand Down Expand Up @@ -603,7 +609,7 @@ impl FloatingPanes {
},
None => {
// TODO: can this happen?
self.active_panes.clear();
self.active_panes.clear(&mut self.panes);
self.z_indices.clear();
},
}
Expand Down Expand Up @@ -673,7 +679,7 @@ impl FloatingPanes {
},
None => {
// TODO: can this happen?
self.active_panes.clear();
self.active_panes.clear(&mut self.panes);
self.z_indices.clear();
},
}
Expand Down Expand Up @@ -743,7 +749,7 @@ impl FloatingPanes {
},
None => {
// TODO: can this happen?
self.active_panes.clear();
self.active_panes.clear(&mut self.panes);
self.z_indices.clear();
},
}
Expand Down Expand Up @@ -816,7 +822,8 @@ impl FloatingPanes {
if active_pane_id == pane_id {
match next_active_pane {
Some(next_active_pane) => {
self.active_panes.insert(client_id, next_active_pane);
self.active_panes
.insert(client_id, next_active_pane, &mut self.panes);
self.focus_pane(next_active_pane, client_id);
},
None => {
Expand All @@ -830,20 +837,22 @@ impl FloatingPanes {
let connected_clients: Vec<ClientId> =
self.connected_clients.borrow().iter().copied().collect();
for client_id in connected_clients {
self.active_panes.insert(client_id, pane_id);
self.active_panes
.insert(client_id, pane_id, &mut self.panes);
}
self.z_indices.retain(|p_id| *p_id != pane_id);
self.z_indices.push(pane_id);
self.set_pane_active_at(pane_id);
self.set_force_render();
}
pub fn focus_pane(&mut self, pane_id: PaneId, client_id: ClientId) {
self.active_panes.insert(client_id, pane_id);
self.active_panes
.insert(client_id, pane_id, &mut self.panes);
self.focus_pane_for_all_clients(pane_id);
}
pub fn defocus_pane(&mut self, pane_id: PaneId, client_id: ClientId) {
self.z_indices.retain(|p_id| *p_id != pane_id);
self.active_panes.remove(&client_id);
self.active_panes.remove(&client_id, &mut self.panes);
self.set_force_render();
}
pub fn get_pane(&self, pane_id: PaneId) -> Option<&Box<dyn Pane>> {
Expand Down Expand Up @@ -960,8 +969,9 @@ impl FloatingPanes {
.map(|(cid, _pid)| *cid)
.collect();
for client_id in clients_in_pane {
self.active_panes.remove(&client_id);
self.active_panes.insert(client_id, to_pane_id);
self.active_panes.remove(&client_id, &mut self.panes);
self.active_panes
.insert(client_id, to_pane_id, &mut self.panes);
}
}
}
23 changes: 23 additions & 0 deletions zellij-server/src/panes/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ pub struct Grid {
scrollback_buffer_lines: usize,
pub mouse_mode: MouseMode,
pub mouse_tracking: MouseTracking,
pub focus_event_tracking: bool,
pub search_results: SearchResult,
pub pending_clipboard_update: Option<String>,
}
Expand Down Expand Up @@ -497,6 +498,7 @@ impl Grid {
scrollback_buffer_lines: 0,
mouse_mode: MouseMode::default(),
mouse_tracking: MouseTracking::default(),
focus_event_tracking: false,
character_cell_size,
search_results: Default::default(),
sixel_grid,
Expand Down Expand Up @@ -1533,6 +1535,7 @@ impl Grid {
self.sixel_scrolling = false;
self.mouse_mode = MouseMode::NoEncoding;
self.mouse_tracking = MouseTracking::Off;
self.focus_event_tracking = false;
self.cursor_is_hidden = false;
if let Some(images_to_reap) = self.sixel_grid.clear() {
self.sixel_grid.reap_images(images_to_reap);
Expand Down Expand Up @@ -1942,6 +1945,20 @@ impl Grid {
pub fn is_alternate_mode_active(&self) -> bool {
self.alternate_screen_state.is_some()
}
pub fn focus_event(&self) -> Option<String> {
if self.focus_event_tracking {
Some("\u{1b}[I".into())
} else {
None
}
}
pub fn unfocus_event(&self) -> Option<String> {
if self.focus_event_tracking {
Some("\u{1b}[O".into())
} else {
None
}
}
}

impl Perform for Grid {
Expand Down Expand Up @@ -2356,6 +2373,9 @@ impl Perform for Grid {
1003 => {
// TBD: any-even mouse tracking
},
1004 => {
self.focus_event_tracking = false;
},
1005 => {
self.mouse_mode = MouseMode::NoEncoding;
},
Expand Down Expand Up @@ -2450,6 +2470,9 @@ impl Perform for Grid {
1003 => {
// TBD: any-even mouse tracking
},
1004 => {
self.focus_event_tracking = true;
},
1005 => {
self.mouse_mode = MouseMode::Utf8;
},
Expand Down
2 changes: 2 additions & 0 deletions zellij-server/src/panes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ pub mod selection;
pub mod sixel;
pub mod terminal_character;

mod active_panes;
mod floating_panes;
mod plugin_pane;
mod search;
mod terminal_pane;
mod tiled_panes;

pub use active_panes::*;
pub use alacritty_functions::*;
pub use floating_panes::*;
pub use grid::*;
Expand Down
6 changes: 6 additions & 0 deletions zellij-server/src/panes/terminal_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,12 @@ impl Pane for TerminalPane {
fn mouse_scroll_down(&self, position: &Position) -> Option<String> {
self.grid.mouse_scroll_down_signal(position)
}
fn focus_event(&self) -> Option<String> {
self.grid.focus_event()
}
fn unfocus_event(&self) -> Option<String> {
self.grid.unfocus_event()
}
fn get_line_number(&self) -> Option<usize> {
// + 1 because the absolute position in the scrollback is 0 indexed and this should be 1 indexed
Some(self.grid.absolute_position_in_scrollback() + 1)
Expand Down
Loading

0 comments on commit 8d1a497

Please sign in to comment.