Skip to content

Commit dea4aba

Browse files
committed
feat: add clear buffer action
Adds a new action that clears both the visible screen and scrollback buffer while preserving any wrapped lines above the cursor. Default key-binding: Ctrl+Alt+K. I used AI to guide the walk‑back logic and research `WRAPLINE` flag placement. All final code, design decisions, and testing are mine.
1 parent cf05926 commit dea4aba

4 files changed

Lines changed: 51 additions & 2 deletions

File tree

i18n/en/cosmic_term.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ copy = Copy
117117
paste = Paste
118118
select-all = Select all
119119
find = Find
120+
clear-buffer = Clear buffer
120121
clear-scrollback = Clear scrollback
121122
122123
## Open

src/main.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
// Copyright 2023 System76 <info@system76.com>
22
// SPDX-License-Identifier: GPL-3.0-only
33

4-
use alacritty_terminal::{event::Event as TermEvent, term, term::color::Colors as TermColors, tty};
4+
use alacritty_terminal::{
5+
event::Event as TermEvent,
6+
grid::{Dimensions, GridCell},
7+
index::Line,
8+
term::{self, color::Colors as TermColors},
9+
tty,
10+
};
511
use cosmic::iced::clipboard::dnd::DndAction;
612
use cosmic::iced::core::keyboard::key::Named;
713
use cosmic::widget::menu::action::MenuAction;
@@ -238,6 +244,7 @@ pub struct Flags {
238244
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
239245
pub enum Action {
240246
About,
247+
ClearBuffer,
241248
ClearScrollback,
242249
ColorSchemes(ColorSchemeKind),
243250
Copy,
@@ -289,6 +296,7 @@ impl Action {
289296
fn message(&self, entity_opt: Option<segmented_button::Entity>) -> Message {
290297
match self {
291298
Self::About => Message::ToggleContextPage(ContextPage::About),
299+
Self::ClearBuffer => Message::ClearBuffer(entity_opt),
292300
Self::ClearScrollback => Message::ClearScrollback(entity_opt),
293301
Self::ColorSchemes(color_scheme_kind) => {
294302
Message::ToggleContextPage(ContextPage::ColorSchemes(*color_scheme_kind))
@@ -352,6 +360,7 @@ impl MenuAction for Action {
352360
#[derive(Clone, Debug)]
353361
pub enum Message {
354362
AppTheme(AppTheme),
363+
ClearBuffer(Option<segmented_button::Entity>),
355364
ClearScrollback(Option<segmented_button::Entity>),
356365
ColorSchemeCollapse,
357366
ColorSchemeDelete(ColorSchemeKind, ColorSchemeId),
@@ -1960,6 +1969,38 @@ impl Application for App {
19601969
config_set!(app_theme, app_theme);
19611970
return self.update_config();
19621971
}
1972+
Message::ClearBuffer(entity_opt) => {
1973+
if let Some(tab_model) = self.pane_model.active() {
1974+
let entity = entity_opt.unwrap_or_else(|| tab_model.active());
1975+
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
1976+
let mut terminal = terminal.lock().unwrap();
1977+
let mut term = terminal.term.lock();
1978+
let grid = term.grid_mut();
1979+
let point = grid.cursor.point;
1980+
let mut line = point.line;
1981+
// Include any wrapped lines above the cursor.
1982+
while line > grid.topmost_line()
1983+
&& grid[line - Line(1)]
1984+
.last()
1985+
.is_some_and(|c| c.flags().contains(term::cell::Flags::WRAPLINE))
1986+
{
1987+
line -= 1;
1988+
}
1989+
let saved_rows: Vec<_> = (line.0..=grid.cursor.point.line.0)
1990+
.map(|i| grid[Line(i)].clone())
1991+
.collect();
1992+
grid.reset();
1993+
let new_line = saved_rows.len() - 1;
1994+
for (i, row) in saved_rows.into_iter().enumerate() {
1995+
grid[Line(i as i32)] = row;
1996+
}
1997+
grid.cursor.point.line = Line(new_line as i32);
1998+
grid.cursor.point.column = point.column;
1999+
drop(term);
2000+
terminal.needs_update = true;
2001+
}
2002+
}
2003+
}
19632004
Message::ClearScrollback(entity_opt) => {
19642005
if let Some(tab_model) = self.pane_model.active() {
19652006
let entity = entity_opt.unwrap_or_else(|| tab_model.active());

src/menu.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub fn context_menu<'a>(
8181
Element::from(menu_item(fl!("paste"), Action::Paste)),
8282
Element::from(menu_item(fl!("select-all"), Action::SelectAll)),
8383
Element::from(divider::horizontal::light()),
84+
Element::from(menu_item(fl!("clear-buffer"), Action::ClearBuffer)),
8485
Element::from(menu_item(fl!("clear-scrollback"), Action::ClearScrollback)),
8586
Element::from(divider::horizontal::light()),
8687
Element::from(menu_item(
@@ -236,6 +237,7 @@ pub fn menu_bar<'a>(
236237
MenuItem::Button(fl!("paste"), None, Action::Paste),
237238
MenuItem::Button(fl!("select-all"), None, Action::SelectAll),
238239
MenuItem::Divider,
240+
MenuItem::Button(fl!("clear-buffer"), None, Action::ClearBuffer),
239241
MenuItem::Button(fl!("clear-scrollback"), None, Action::ClearScrollback),
240242
MenuItem::Divider,
241243
MenuItem::Button(fl!("find"), None, Action::Find),

src/shortcuts.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl Binding {
5757
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
5858
pub enum KeyBindAction {
5959
Disable,
60+
ClearBuffer,
6061
ClearScrollback,
6162
Copy,
6263
CopyOrSigint,
@@ -99,6 +100,7 @@ impl KeyBindAction {
99100
fn to_action(self) -> Option<Action> {
100101
match self {
101102
Self::Disable => None,
103+
Self::ClearBuffer => Some(Action::ClearBuffer),
102104
Self::ClearScrollback => Some(Action::ClearScrollback),
103105
Self::Copy => Some(Action::Copy),
104106
Self::CopyOrSigint => Some(Action::CopyOrSigint),
@@ -259,6 +261,7 @@ impl ShortcutsConfig {
259261
pub fn action_label(action: KeyBindAction) -> String {
260262
match action {
261263
KeyBindAction::Disable => fl!("disable"),
264+
KeyBindAction::ClearBuffer => fl!("clear-buffer"),
262265
KeyBindAction::ClearScrollback => fl!("clear-scrollback"),
263266
KeyBindAction::Copy => fl!("copy"),
264267
KeyBindAction::CopyOrSigint => fl!("copy-or-sigint"),
@@ -362,7 +365,7 @@ pub fn shortcut_groups() -> Vec<ShortcutGroup> {
362365
KeyBindAction::ZoomReset,
363366
],
364367
});
365-
let mut other_actions = vec![KeyBindAction::ClearScrollback];
368+
let mut other_actions = vec![KeyBindAction::ClearBuffer, KeyBindAction::ClearScrollback];
366369
#[cfg(feature = "password_manager")]
367370
other_actions.push(KeyBindAction::PasswordManager);
368371
groups.push(ShortcutGroup {
@@ -497,6 +500,8 @@ fn fallback_shortcuts() -> Shortcuts {
497500
bind!([Ctrl, Shift], "ArrowRight", PaneFocusRight);
498501
bind!([Ctrl, Shift], "L", PaneFocusRight);
499502

503+
// CTRL+Alt+K clears the screen and entire buffer.
504+
bind!([Ctrl, Alt], "K", ClearBuffer);
500505
// CTRL+Alt+L clears the scrollback.
501506
bind!([Ctrl, Alt], "L", ClearScrollback);
502507

0 commit comments

Comments
 (0)