zellij/default-plugins/session-manager/src/main.rs
Aram Drevekenin 4c6b03acc1
feat(sessions): resurrect sessions through the session-manager (and plugin API) (#2902)
* working with table and scrolling

* ui and functionality complete

* fix formatting

* refactor: background jobs

* style(fmt): rustfmt
2023-11-04 11:20:50 +01:00

255 lines
9.3 KiB
Rust

mod resurrectable_sessions;
mod session_list;
mod ui;
use zellij_tile::prelude::*;
use std::collections::BTreeMap;
use ui::{
components::{
render_controls_line, render_new_session_line, render_prompt, render_resurrection_toggle,
Colors,
},
SessionUiInfo,
};
use resurrectable_sessions::ResurrectableSessions;
use session_list::SessionList;
#[derive(Default)]
struct State {
session_name: Option<String>,
sessions: SessionList,
resurrectable_sessions: ResurrectableSessions,
search_term: String,
new_session_name: Option<String>,
browsing_resurrection_sessions: bool,
colors: Colors,
}
register_plugin!(State);
impl ZellijPlugin for State {
fn load(&mut self, _configuration: BTreeMap<String, String>) {
subscribe(&[
EventType::ModeUpdate,
EventType::SessionUpdate,
EventType::Key,
EventType::RunCommandResult,
]);
}
fn update(&mut self, event: Event) -> bool {
let mut should_render = false;
match event {
Event::ModeUpdate(mode_info) => {
self.colors = Colors::new(mode_info.style.colors);
should_render = true;
},
Event::Key(key) => {
should_render = self.handle_key(key);
},
Event::PermissionRequestResult(_result) => {
should_render = true;
},
Event::SessionUpdate(session_infos, resurrectable_session_list) => {
self.resurrectable_sessions
.update(resurrectable_session_list);
self.update_session_infos(session_infos);
should_render = true;
},
_ => (),
};
should_render
}
fn render(&mut self, rows: usize, cols: usize) {
if self.browsing_resurrection_sessions {
self.resurrectable_sessions.render(rows, cols);
return;
}
render_resurrection_toggle(cols, false);
render_prompt(
self.new_session_name.is_some(),
&self.search_term,
self.colors,
);
let room_for_list = rows.saturating_sub(5); // search line and controls
self.sessions.update_rows(room_for_list);
let list = self
.sessions
.render(room_for_list, cols.saturating_sub(7), self.colors); // 7 for various ui
for line in list {
println!("{}", line.render());
}
render_new_session_line(
&self.new_session_name,
self.sessions.is_searching,
self.colors,
);
render_controls_line(self.sessions.is_searching, rows, cols, self.colors);
}
}
impl State {
fn reset_selected_index(&mut self) {
self.sessions.reset_selected_index();
}
fn handle_key(&mut self, key: Key) -> bool {
let mut should_render = false;
if let Key::Right = key {
if self.new_session_name.is_none() {
self.sessions.result_expand();
}
should_render = true;
} else if let Key::Left = key {
if self.new_session_name.is_none() {
self.sessions.result_shrink();
}
should_render = true;
} else if let Key::Down = key {
if self.browsing_resurrection_sessions {
self.resurrectable_sessions.move_selection_down();
} else if self.new_session_name.is_none() {
self.sessions.move_selection_down();
}
should_render = true;
} else if let Key::Up = key {
if self.browsing_resurrection_sessions {
self.resurrectable_sessions.move_selection_up();
} else if self.new_session_name.is_none() {
self.sessions.move_selection_up();
}
should_render = true;
} else if let Key::Char(character) = key {
if character == '\n' {
self.handle_selection();
} else if let Some(new_session_name) = self.new_session_name.as_mut() {
new_session_name.push(character);
} else if self.browsing_resurrection_sessions {
self.resurrectable_sessions.handle_character(character);
} else {
self.search_term.push(character);
self.sessions
.update_search_term(&self.search_term, &self.colors);
}
should_render = true;
} else if let Key::Backspace = key {
if let Some(new_session_name) = self.new_session_name.as_mut() {
if new_session_name.is_empty() {
self.new_session_name = None;
} else {
new_session_name.pop();
}
} else if self.browsing_resurrection_sessions {
self.resurrectable_sessions.handle_backspace();
} else {
self.search_term.pop();
self.sessions
.update_search_term(&self.search_term, &self.colors);
}
should_render = true;
} else if let Key::Ctrl('w') = key {
if self.sessions.is_searching {
// no-op
} else if self.new_session_name.is_some() {
self.new_session_name = None;
} else {
self.new_session_name = Some(String::new());
}
should_render = true;
} else if let Key::Ctrl('c') = key {
if let Some(new_session_name) = self.new_session_name.as_mut() {
if new_session_name.is_empty() {
self.new_session_name = None;
} else {
new_session_name.clear()
}
} else if !self.search_term.is_empty() {
self.search_term.clear();
self.sessions
.update_search_term(&self.search_term, &self.colors);
self.reset_selected_index();
} else {
self.reset_selected_index();
hide_self();
}
should_render = true;
} else if let Key::BackTab = key {
self.browsing_resurrection_sessions = !self.browsing_resurrection_sessions;
should_render = true;
} else if let Key::Delete = key {
if self.browsing_resurrection_sessions {
self.resurrectable_sessions.delete_selected_session();
should_render = true;
}
} else if let Key::Ctrl('d') = key {
if self.browsing_resurrection_sessions {
self.resurrectable_sessions
.show_delete_all_sessions_warning();
should_render = true;
}
} else if let Key::Esc = key {
hide_self();
}
should_render
}
fn handle_selection(&mut self) {
if self.browsing_resurrection_sessions {
if let Some(session_name_to_resurrect) =
self.resurrectable_sessions.get_selected_session_name()
{
switch_session(Some(&session_name_to_resurrect));
}
} else if let Some(new_session_name) = &self.new_session_name {
if new_session_name.is_empty() {
switch_session(None);
} else if self.session_name.as_ref() == Some(new_session_name) {
// noop - we're already here!
self.new_session_name = None;
} else {
switch_session(Some(new_session_name));
}
} else if let Some(selected_session_name) = self.sessions.get_selected_session_name() {
let selected_tab = self.sessions.get_selected_tab_position();
let selected_pane = self.sessions.get_selected_pane_id();
let is_current_session = self.sessions.selected_is_current_session();
if is_current_session {
if let Some((pane_id, is_plugin)) = selected_pane {
if is_plugin {
focus_plugin_pane(pane_id, true);
} else {
focus_terminal_pane(pane_id, true);
}
} else if let Some(tab_position) = selected_tab {
go_to_tab(tab_position as u32);
}
} else {
switch_session_with_focus(&selected_session_name, selected_tab, selected_pane);
}
}
self.reset_selected_index();
self.new_session_name = None;
self.search_term.clear();
self.sessions
.update_search_term(&self.search_term, &self.colors);
hide_self();
}
fn update_session_infos(&mut self, session_infos: Vec<SessionInfo>) {
let session_infos: Vec<SessionUiInfo> = session_infos
.iter()
.map(|s| SessionUiInfo::from_session_info(s))
.collect();
let current_session_name = session_infos.iter().find_map(|s| {
if s.is_current_session {
Some(s.name.clone())
} else {
None
}
});
if let Some(current_session_name) = current_session_name {
self.session_name = Some(current_session_name);
}
self.sessions.set_sessions(session_infos);
}
}