Skip to content

Commit

Permalink
feat: add RenameSession mode and related actions
Browse files Browse the repository at this point in the history
  • Loading branch information
thrombe committed Dec 20, 2024
1 parent 1923bac commit 692f5c5
Show file tree
Hide file tree
Showing 18 changed files with 177 additions and 4 deletions.
2 changes: 1 addition & 1 deletion default-plugins/status-bar/src/first_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ fn get_key_shortcut_for_mode<'a>(
InputMode::Resize => KeyAction::Resize,
InputMode::Move => KeyAction::Move,
InputMode::Scroll | InputMode::Search | InputMode::EnterSearch => KeyAction::Search,
InputMode::Session => KeyAction::Session,
InputMode::Session | InputMode::RenameSession => KeyAction::Session,
};
for shortcut in shortcuts.iter_mut() {
if shortcut.action == key_action {
Expand Down
3 changes: 2 additions & 1 deletion default-plugins/status-bar/src/one_line_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,7 @@ fn add_keygroup_separator(help: &ModeInfo, max_len: usize) -> Option<LinePart> {
let mode_help_text = match help.mode {
InputMode::RenamePane => Some("RENAMING PANE"),
InputMode::RenameTab => Some("RENAMING TAB"),
InputMode::RenameSession => Some("RENAMING SESSION"),
InputMode::EnterSearch => Some("ENTERING SEARCH TERM"),
InputMode::Search => Some("SEARCHING"),
_ => None,
Expand Down Expand Up @@ -1290,7 +1291,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<KeyWithModifier
(s("Previous Tab"), s("Previous"), action_key(&km, &[A::GoToPreviousTab, TO_NORMAL])),
(s("Next Tab"), s("Next"), action_key(&km, &[A::GoToNextTab, TO_NORMAL])),
(s("Select pane"), s("Select"), to_basemode_key),
]} else if matches!(mi.mode, IM::RenamePane | IM::RenameTab) { vec![
]} else if matches!(mi.mode, IM::RenamePane | IM::RenameTab | IM::RenameSession) { vec![
(s("When done"), s("Done"), to_basemode_key),
]} else { vec![] }
}
Expand Down
4 changes: 3 additions & 1 deletion default-plugins/status-bar/src/second_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<KeyWithModifier
]} else if mi.mode == IM::Session { vec![
(s("Detach"), s("Detach"), action_key(&km, &[Action::Detach])),
(s("Session Manager"), s("Manager"), action_key(&km, &[A::LaunchOrFocusPlugin(Default::default(), true, true, false, false), TO_NORMAL])), // not entirely accurate
(s("Rename session"), s("Rename"),
action_key(&km, &[A::SwitchToMode(IM::RenameSession), A::SessionNameInput(vec![0])])),
(s("Select pane"), s("Select"), to_normal_key),
]} else if mi.mode == IM::Tmux { vec![
(s("Move focus"), s("Move"), action_key_group(&km, &[
Expand All @@ -265,7 +267,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<KeyWithModifier
(s("Previous Tab"), s("Previous"), action_key(&km, &[A::GoToPreviousTab, TO_NORMAL])),
(s("Next Tab"), s("Next"), action_key(&km, &[A::GoToNextTab, TO_NORMAL])),
(s("Select pane"), s("Select"), to_normal_key),
]} else if matches!(mi.mode, IM::RenamePane | IM::RenameTab) { vec![
]} else if matches!(mi.mode, IM::RenamePane | IM::RenameSession | IM::RenameTab) { vec![
(s("When done"), s("Done"), to_normal_key),
(s("Select pane"), s("Select"), action_key_group(&km, &[
&[A::MoveFocus(Dir::Left)], &[A::MoveFocus(Dir::Down)],
Expand Down
9 changes: 8 additions & 1 deletion default-plugins/tab-bar/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,15 @@ impl ZellijPlugin for State {
ThemeHue::Light => self.mode_info.style.colors.white,
};

let mut name = self.mode_info.session_name.as_deref();
if self.mode_info.mode == InputMode::RenameSession
&& name.map(|s| s.len() == 0).unwrap_or_default()
{
name = Some("Enter name...");
}

self.tab_line = tab_line(
self.mode_info.session_name.as_deref(),
name,
all_tabs,
active_tab_index,
cols.saturating_sub(1),
Expand Down
6 changes: 6 additions & 0 deletions zellij-client/src/input_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ impl InputHandler {
None,
);
}
if self.mode == InputMode::RenameSession {
self.dispatch_action(
Action::SessionNameInput(pasted_text.as_bytes().to_vec()),
None,
);
}
},
_ => {},
}
Expand Down
10 changes: 10 additions & 0 deletions zellij-server/src/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,16 @@ pub(crate) fn route_action(
.send_to_screen(ScreenInstruction::UndoRenameTab(client_id))
.with_context(err_context)?;
},
Action::SessionNameInput(c) => {
senders
.send_to_screen(ScreenInstruction::UpdateSessionName(c, client_id))
.with_context(err_context)?;
},
Action::UndoRenameSession => {
senders
.send_to_screen(ScreenInstruction::UndoRenameSession(client_id))
.with_context(err_context)?;
},
Action::MoveTab(direction) => {
let screen_instr = match direction {
Direction::Left => ScreenInstruction::MoveTabLeft(client_id),
Expand Down
88 changes: 88 additions & 0 deletions zellij-server/src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ pub enum ScreenInstruction {
ToggleTab(ClientId),
UpdateTabName(Vec<u8>, ClientId),
UndoRenameTab(ClientId),
UpdateSessionName(Vec<u8>, ClientId),
UndoRenameSession(ClientId),
MoveTabLeft(ClientId),
MoveTabRight(ClientId),
TerminalResize(Size),
Expand Down Expand Up @@ -501,6 +503,8 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::GoToTabName(..) => ScreenContext::GoToTabName,
ScreenInstruction::UpdateTabName(..) => ScreenContext::UpdateTabName,
ScreenInstruction::UndoRenameTab(..) => ScreenContext::UndoRenameTab,
ScreenInstruction::UpdateSessionName(..) => ScreenContext::UpdateSessionName,
ScreenInstruction::UndoRenameSession(..) => ScreenContext::UndoRenameSession,
ScreenInstruction::MoveTabLeft(..) => ScreenContext::MoveTabLeft,
ScreenInstruction::MoveTabRight(..) => ScreenContext::MoveTabRight,
ScreenInstruction::TerminalResize(..) => ScreenContext::TerminalResize,
Expand Down Expand Up @@ -689,6 +693,7 @@ pub(crate) struct Screen {
copy_options: CopyOptions,
debug: bool,
session_name: String,
visual_session_name: Option<String>,
session_infos_on_machine: BTreeMap<String, SessionInfo>, // String is the session name, can
// also be this session
resurrectable_sessions: BTreeMap<String, Duration>, // String is the session name, duration is
Expand Down Expand Up @@ -753,6 +758,7 @@ impl Screen {
copy_options,
debug,
session_name,
visual_session_name: None,
session_infos_on_machine,
default_layout,
default_layout_name,
Expand Down Expand Up @@ -1674,6 +1680,70 @@ impl Screen {
Ok(())
}

pub fn update_visual_session_rename(
&mut self,
buf: Vec<u8>,
client_id: ClientId,
) -> Result<()> {
let err_context = || format!("failed to update session name for client id: {client_id:?}");

let s = str::from_utf8(&buf)
.with_context(|| format!("failed to construct tab name from buf: {buf:?}"))
.with_context(err_context)?;

if self.visual_session_name.is_none() {
self.visual_session_name = Some(String::new());
}
let name = self.visual_session_name.as_mut().unwrap();

match s {
"\0" => {
*name = String::new();
},
"\u{007F}" | "\u{0008}" => {
// delete and backspace keys
name.pop();
},
c => {
// It only allows printable unicode
if buf.iter().all(|u| matches!(u, 0x20..=0x7E | 0xA0..=0xFF)) {
name.push_str(c);
}
},
}

self.generate_and_report_mode_info(client_id, self.visual_session_name.clone())
.with_context(err_context)
}

pub fn undo_visual_session_rename(&mut self, client_id: ClientId) -> Result<()> {
let err_context = || format!("failed to undo session rename for client {}", client_id);
_ = self.visual_session_name.take();
self.generate_and_report_mode_info(client_id, Some(self.session_name.clone()))
.with_context(err_context)
}

pub fn generate_and_report_mode_info(
&mut self,
client_id: ClientId,
name: Option<String>,
) -> Result<()> {
let mut mode_info = self
.mode_info
.get(&client_id)
.unwrap_or(&self.default_mode_info)
.clone();
mode_info.session_name = name;
self.bus
.senders
.send_to_plugin(PluginInstruction::Update(vec![(
None,
Some(client_id),
Event::ModeUpdate(mode_info),
)]))
.context("Failed to report mode info")
}

pub fn update_active_tab_name(&mut self, buf: Vec<u8>, client_id: ClientId) -> Result<()> {
let err_context =
|| format!("failed to update active tabs name for client id: {client_id:?}");
Expand Down Expand Up @@ -1911,6 +1981,14 @@ impl Screen {
}
}

if mode_info.mode == InputMode::RenameSession {
self.visual_session_name = Some(self.session_name.clone());
} else if let Some(name) = self.visual_session_name.take() {
self.bus
.senders
.send_to_screen(ScreenInstruction::RenameSession(name, client_id))?;
}

self.style = mode_info.style;
self.mode_info.insert(client_id, mode_info.clone());
for tab in self.tabs.values_mut() {
Expand Down Expand Up @@ -3651,6 +3729,16 @@ pub(crate) fn screen_thread_main(
screen.unblock_input()?;
screen.render(None)?;
},
ScreenInstruction::UpdateSessionName(c, client_id) => {
screen.update_visual_session_rename(c, client_id)?;
screen.unblock_input()?;
screen.render(None)?;
},
ScreenInstruction::UndoRenameSession(client_id) => {
screen.undo_visual_session_rename(client_id)?;
screen.unblock_input()?;
screen.render(None)?;
},
ScreenInstruction::MoveTabLeft(client_id) => {
if pending_tab_ids.is_empty() {
screen.move_active_tab_to_left(client_id)?;
Expand Down
6 changes: 6 additions & 0 deletions zellij-utils/assets/prost/api.action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,8 @@ pub enum ActionName {
MoveTab = 83,
KeybindPipe = 84,
TogglePanePinned = 85,
SessionNameInput = 86,
UndoRenameSession = 87,
}
impl ActionName {
/// String value of the enum field names used in the ProtoBuf definition.
Expand Down Expand Up @@ -550,6 +552,8 @@ impl ActionName {
ActionName::MoveTab => "MoveTab",
ActionName::KeybindPipe => "KeybindPipe",
ActionName::TogglePanePinned => "TogglePanePinned",
ActionName::SessionNameInput => "SessionNameInput",
ActionName::UndoRenameSession => "UndoRenameSession",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
Expand Down Expand Up @@ -641,6 +645,8 @@ impl ActionName {
"MoveTab" => Some(Self::MoveTab),
"KeybindPipe" => Some(Self::KeybindPipe),
"TogglePanePinned" => Some(Self::TogglePanePinned),
"SessionNameInput" => Some(Self::SessionNameInput),
"UndoRenameSession" => Some(Self::UndoRenameSession),
_ => None,
}
}
Expand Down
4 changes: 4 additions & 0 deletions zellij-utils/assets/prost/api.input_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub enum InputMode {
Prompt = 12,
/// / `Tmux` mode allows for basic tmux keybindings functionality
Tmux = 13,
/// / `RenameSession` mode allows assigning a new name to active session.
RenameSession = 14,
}
impl InputMode {
/// String value of the enum field names used in the ProtoBuf definition.
Expand All @@ -59,6 +61,7 @@ impl InputMode {
InputMode::Move => "Move",
InputMode::Prompt => "Prompt",
InputMode::Tmux => "Tmux",
InputMode::RenameSession => "RenameSession",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
Expand All @@ -78,6 +81,7 @@ impl InputMode {
"Move" => Some(Self::Move),
"Prompt" => Some(Self::Prompt),
"Tmux" => Some(Self::Tmux),
"RenameSession" => Some(Self::RenameSession),
_ => None,
}
}
Expand Down
4 changes: 4 additions & 0 deletions zellij-utils/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,9 @@ pub enum InputMode {
/// `RenamePane` mode allows assigning a new name to a pane.
#[serde(alias = "renamepane")]
RenamePane,
/// `RenameSession` mode allows assigning a new name to a session.
#[serde(alias = "renamesession")]
RenameSession,
/// `Session` mode allows detaching sessions
#[serde(alias = "session")]
Session,
Expand Down Expand Up @@ -1087,6 +1090,7 @@ impl FromStr for InputMode {
"scroll" | "Scroll" => Ok(InputMode::Scroll),
"renametab" | "RenameTab" => Ok(InputMode::RenameTab),
"renamepane" | "RenamePane" => Ok(InputMode::RenamePane),
"renamesession" | "RenameSession" => Ok(InputMode::RenameSession),
"session" | "Session" => Ok(InputMode::Session),
"move" | "Move" => Ok(InputMode::Move),
"prompt" | "Prompt" => Ok(InputMode::Prompt),
Expand Down
2 changes: 2 additions & 0 deletions zellij-utils/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ pub enum ScreenContext {
GoToTabName,
UpdateTabName,
UndoRenameTab,
UpdateSessionName,
UndoRenameSession,
MoveTabLeft,
MoveTabRight,
TerminalResize,
Expand Down
2 changes: 2 additions & 0 deletions zellij-utils/src/input/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ pub enum Action {
CloseFocus,
PaneNameInput(Vec<u8>),
UndoRenamePane,
SessionNameInput(Vec<u8>),
UndoRenameSession,
/// Create a new tab, optionally with a specified tab layout.
NewTab(
Option<TiledPaneLayout>,
Expand Down
1 change: 1 addition & 0 deletions zellij-utils/src/input/keybinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl Keybinds {
},
InputMode::RenameTab => Action::TabNameInput(raw_bytes),
InputMode::RenamePane => Action::PaneNameInput(raw_bytes),
InputMode::RenameSession => Action::SessionNameInput(raw_bytes),
InputMode::EnterSearch => Action::SearchInput(raw_bytes),
_ => Action::NoOp,
}
Expand Down
16 changes: 16 additions & 0 deletions zellij-utils/src/kdl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ macro_rules! parse_kdl_action_arguments {
"CloseTab" => Ok(Action::CloseTab),
"ToggleTab" => Ok(Action::ToggleTab),
"UndoRenameTab" => Ok(Action::UndoRenameTab),
"UndoRenameSession" => Ok(Action::UndoRenameSession),
"Detach" => Ok(Action::Detach),
"Copy" => Ok(Action::Copy),
"Confirm" => Ok(Action::Confirm),
Expand Down Expand Up @@ -414,6 +415,7 @@ impl Action {
"Write" => Ok(Action::Write(None, bytes, false)),
"PaneNameInput" => Ok(Action::PaneNameInput(bytes)),
"TabNameInput" => Ok(Action::TabNameInput(bytes)),
"SessionNameInput" => Ok(Action::SessionNameInput(bytes)),
"SearchInput" => Ok(Action::SearchInput(bytes)),
"GoToTab" => {
let tab_index = *bytes.get(0).ok_or_else(|| {
Expand Down Expand Up @@ -728,6 +730,14 @@ impl Action {
Some(node)
},
Action::UndoRenameTab => Some(KdlNode::new("UndoRenameTab")),
Action::SessionNameInput(bytes) => {
let mut node = KdlNode::new("SessionNameInput");
for byte in bytes {
node.push(KdlValue::Base10(*byte as i64));
}
Some(node)
},
Action::UndoRenameSession => Some(KdlNode::new("UndoRenameSession")),
Action::MoveTab(direction) => {
let mut node = KdlNode::new("MoveTab");
let direction = match direction {
Expand Down Expand Up @@ -1298,6 +1308,9 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
"UndoRenamePane" => {
parse_kdl_action_arguments!(action_name, action_arguments, kdl_action)
},
"UndoRenameSession" => {
parse_kdl_action_arguments!(action_name, action_arguments, kdl_action)
},
"NoOp" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action),
"GoToNextTab" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action),
"GoToPreviousTab" => {
Expand Down Expand Up @@ -1475,6 +1488,9 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
"TabNameInput" => {
parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action)
},
"SessionNameInput" => {
parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action)
},
"SearchInput" => {
parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action)
},
Expand Down
2 changes: 2 additions & 0 deletions zellij-utils/src/plugin_api/action.proto
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ enum ActionName {
MoveTab = 83;
KeybindPipe = 84;
TogglePanePinned = 85;
SessionNameInput = 86;
UndoRenameSession = 87;
}

message Position {
Expand Down
Loading

0 comments on commit 692f5c5

Please sign in to comment.