Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ClearScrollback to replicate macOS Cmd+K behavior #1768

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions zellij-client/src/input_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ impl InputHandler {
},
Action::CloseFocus
| Action::ClearScreen
| Action::ClearScrollback(_)
| Action::NewPane(..)
| Action::Run(_)
| Action::NewTiledPane(..)
Expand Down
26 changes: 26 additions & 0 deletions zellij-server/src/panes/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,32 @@ impl Grid {
self.reset_terminal_state();
self.mark_for_rerender();
}
/// Clears the scrollback and positions the current active line on top of the pane.
pub fn clear_scrollback(&mut self, offset: i32) {
if self.alternate_screen_state.is_some() {
log::warn!("Tried to clear scrollback of pane with alternate_screen_state");
return;
}

let new_viewport = self
.viewport
.clone()
.into_iter()
.skip(self.viewport.len().saturating_sub(offset as usize + 1))
.collect::<Vec<_>>();

self.clear_viewport_before_rendering = true;
self.lines_above = VecDeque::new();
self.lines_below = vec![];
self.viewport = vec![Row::new().canonical()];
self.scroll_region = None;
self.scrollback_buffer_lines = 0;
self.viewport = new_viewport;
self.cursor.y = offset as usize;
self.output_buffer.update_all_lines();

self.mark_for_rerender();
}
/// Dumps all lines above terminal vieport and the viewport itself to a string
pub fn dump_screen(&mut self, full: bool) -> String {
let viewport: String = dump_screen!(self.viewport);
Expand Down
3 changes: 3 additions & 0 deletions zellij-server/src/panes/plugin_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,9 @@ impl Pane for PluginPane {
fn clear_scroll(&mut self) {
// noop
}
fn clear_scrollback(&mut self, _offset: i32) {
// noop
}
fn start_selection(&mut self, start: &Position, client_id: ClientId) {
self.send_plugin_instructions
.send(PluginInstruction::Update(vec![(
Expand Down
3 changes: 3 additions & 0 deletions zellij-server/src/panes/terminal_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,9 @@ impl Pane for TerminalPane {
fn clear_screen(&mut self) {
self.grid.clear_screen()
}
fn clear_scrollback(&mut self, offset: i32) {
self.grid.clear_scrollback(offset)
}
fn scroll_up(&mut self, count: usize, _client_id: ClientId) {
self.grid.move_viewport_up(count);
self.set_should_render(true);
Expand Down
12 changes: 12 additions & 0 deletions zellij-server/src/plugins/zellij_exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,18 @@ fn clear_screen(env: &ForeignFunctionEnv) {
let action = Action::ClearScreen;
apply_action!(action, error_msg, env);
}

fn clear_scrollback(env: &ForeignFunctionEnv, offset: i32) {
let error_msg = || {
format!(
"failed to clear scrollback in plugin {}",
env.plugin_env.name()
)
};
let action = Action::ClearScrollback(offset);
apply_action!(action, error_msg, env);
}

fn scroll_up(env: &ForeignFunctionEnv) {
let error_msg = || format!("failed to scroll up in plugin {}", env.plugin_env.name());
let action = Action::ScrollUp;
Expand Down
5 changes: 5 additions & 0 deletions zellij-server/src/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ pub(crate) fn route_action(
.send_to_screen(ScreenInstruction::ClearScreen(client_id))
.with_context(err_context)?;
},
Action::ClearScrollback(offset) => {
senders
.send_to_screen(ScreenInstruction::ClearScrollback(client_id, offset))
.with_context(err_context)?;
},
Action::DumpScreen(val, full) => {
senders
.send_to_screen(ScreenInstruction::DumpScreen(val, client_id, full))
Expand Down
15 changes: 15 additions & 0 deletions zellij-server/src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ pub enum ScreenInstruction {
MovePaneLeft(ClientId),
Exit,
ClearScreen(ClientId),
ClearScrollback(ClientId, i32),
DumpScreen(String, ClientId, bool),
EditScrollback(ClientId),
ScrollUp(ClientId),
Expand Down Expand Up @@ -366,6 +367,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::MovePaneLeft(..) => ScreenContext::MovePaneLeft,
ScreenInstruction::Exit => ScreenContext::Exit,
ScreenInstruction::ClearScreen(..) => ScreenContext::ClearScreen,
ScreenInstruction::ClearScrollback(..) => ScreenContext::ClearScrollback,
ScreenInstruction::DumpScreen(..) => ScreenContext::DumpScreen,
ScreenInstruction::EditScrollback(..) => ScreenContext::EditScrollback,
ScreenInstruction::ScrollUp(..) => ScreenContext::ScrollUp,
Expand Down Expand Up @@ -2247,6 +2249,19 @@ pub(crate) fn screen_thread_main(
screen.render()?;
screen.unblock_input()?;
},
ScreenInstruction::ClearScrollback(client_id, offset) => {
active_tab_and_connected_client_id!(
screen,
client_id,
|tab: &mut Tab, client_id: ClientId| tab.clear_scrollback_active_terminal_screen(
client_id,
offset,
),
?
);
screen.render()?;
screen.unblock_input()?;
},
ScreenInstruction::DumpScreen(file, client_id, full) => {
active_tab_and_connected_client_id!(
screen,
Expand Down
11 changes: 11 additions & 0 deletions zellij-server/src/tab/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ pub trait Pane {
fn pull_left(&mut self, count: usize);
fn pull_up(&mut self, count: usize);
fn clear_screen(&mut self);
fn clear_scrollback(&mut self, offset: i32);
fn dump_screen(&mut self, _client_id: ClientId, _full: bool) -> String {
"".to_owned()
}
Expand Down Expand Up @@ -2503,6 +2504,16 @@ impl Tab {
}
Ok(())
}
pub fn clear_scrollback_active_terminal_screen(
&mut self,
client_id: ClientId,
offset: i32,
) -> Result<()> {
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
active_pane.clear_scrollback(offset);
}
Ok(())
}
pub fn dump_active_terminal_screen(
&mut self,
file: Option<String>,
Expand Down
5 changes: 5 additions & 0 deletions zellij-utils/assets/prost/api.action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ pub mod action {
RenamePluginPanePayload(super::IdAndName),
#[prost(message, tag = "44")]
RenameTabPayload(super::IdAndName),
#[prost(message, tag = "45")]
ClearScrollbackPayload(i32),
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
Expand Down Expand Up @@ -400,6 +402,7 @@ pub enum ActionName {
BreakPane = 77,
BreakPaneRight = 78,
BreakPaneLeft = 79,
ClearScrollback = 80,
}
impl ActionName {
/// String value of the enum field names used in the ProtoBuf definition.
Expand All @@ -422,6 +425,7 @@ impl ActionName {
ActionName::MovePane => "MovePane",
ActionName::MovePaneBackwards => "MovePaneBackwards",
ActionName::ClearScreen => "ClearScreen",
ActionName::ClearScrollback => "ClearScrollback",
ActionName::DumpScreen => "DumpScreen",
ActionName::EditScrollback => "EditScrollback",
ActionName::ScrollUp => "ScrollUp",
Expand Down Expand Up @@ -507,6 +511,7 @@ impl ActionName {
"MovePane" => Some(Self::MovePane),
"MovePaneBackwards" => Some(Self::MovePaneBackwards),
"ClearScreen" => Some(Self::ClearScreen),
"ClearScrollback" => Some(Self::ClearScrollback),
"DumpScreen" => Some(Self::DumpScreen),
"EditScrollback" => Some(Self::EditScrollback),
"ScrollUp" => Some(Self::ScrollUp),
Expand Down
6 changes: 6 additions & 0 deletions zellij-utils/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,12 @@ pub enum CliAction {
MovePaneBackwards,
/// Clear all buffers for a focused pane
Clear,
/// Clear the scrollback and positions the current active line on top of the pane.
ClearScrollback {
/// Offset of lines from the current viewport to keep
#[clap(short, long, value_parser, default_value("1"))]
offset: i8,
},
/// Dump the focused pane to a file
DumpScreen {
path: PathBuf,
Expand Down
1 change: 1 addition & 0 deletions zellij-utils/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ pub enum ScreenContext {
MovePaneLeft,
Exit,
ClearScreen,
ClearScrollback,
DumpScreen,
EditScrollback,
ScrollUp,
Expand Down
5 changes: 5 additions & 0 deletions zellij-utils/src/input/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ pub enum Action {
MovePaneBackwards,
/// Clear all buffers of a current screen
ClearScreen,
/// Clear the scrollback and positions the current active line on top of the pane.
ClearScrollback(i32),
/// Dumps the screen to a file
DumpScreen(String, bool),
/// Scroll up in focus pane.
Expand Down Expand Up @@ -276,6 +278,9 @@ impl Action {
CliAction::MovePane { direction } => Ok(vec![Action::MovePane(direction)]),
CliAction::MovePaneBackwards => Ok(vec![Action::MovePaneBackwards]),
CliAction::Clear => Ok(vec![Action::ClearScreen]),
CliAction::ClearScrollback { offset } => {
Ok(vec![Action::ClearScrollback(offset as i32)])
},
CliAction::DumpScreen { path, full } => Ok(vec![Action::DumpScreen(
path.as_os_str().to_string_lossy().into(),
full,
Expand Down
13 changes: 13 additions & 0 deletions zellij-utils/src/kdl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,16 @@ impl Action {
})? as u32;
Ok(Action::GoToTab(tab_index))
},
"ClearScrollback" => {
let offset = *bytes.get(0).ok_or_else(|| {
ConfigError::new_kdl_error(
format!("Missing scrollback offset"),
action_node.span().offset(),
action_node.span().len(),
)
})? as u32;
Ok(Action::ClearScrollback(offset as i32))
},
_ => Err(ConfigError::new_kdl_error(
"Failed to parse action".into(),
action_node.span().offset(),
Expand Down Expand Up @@ -703,6 +713,9 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
"Detach" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action),
"Copy" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action),
"Clear" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action),
"ClearScrollback" => {
parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action)
},
"Confirm" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action),
"Deny" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action),
"Write" => parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action),
Expand Down
4 changes: 4 additions & 0 deletions zellij-utils/src/plugin_api/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,10 @@ impl TryFrom<Action> for ProtobufAction {
name: ProtobufActionName::ClearScreen as i32,
optional_payload: None,
}),
Action::ClearScrollback(offset) => Ok(ProtobufAction {
name: ProtobufActionName::ClearScrollback as i32,
optional_payload: Some(OptionalPayload::ClearScrollbackPayload(offset)),
}),
Action::DumpScreen(file_path, include_scrollback) => Ok(ProtobufAction {
name: ProtobufActionName::DumpScreen as i32,
optional_payload: Some(OptionalPayload::DumpScreenPayload(DumpScreenPayload {
Expand Down