Skip to content

Commit ed095d1

Browse files
committed
Add a way to persist the alternate screen on exit
1 parent f1daee8 commit ed095d1

6 files changed

Lines changed: 54 additions & 5 deletions

File tree

src/core/commands.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub enum Command {
3434

3535
// Configuration options
3636
SetExitStrategy(ExitStrategy),
37+
PersistAlternate(bool),
3738
SetInputClassifier(Box<dyn InputClassifier + Send + Sync + 'static>),
3839
AddExitCallback(Box<dyn FnMut() + Send + Sync + 'static>),
3940
#[cfg(feature = "static_output")]
@@ -70,6 +71,7 @@ impl PartialEq for Command {
7071
impl Debug for Command {
7172
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7273
match self {
74+
Self::PersistAlternate(persist) => write!(f, "PersistAlternate({persist})"),
7375
Self::SetData(text) => write!(f, "SetData({text:?})"),
7476
Self::AppendData(text) => write!(f, "AppendData({text:?})"),
7577
Self::SetPrompt(text) => write!(f, "SetPrompt({text:?})"),

src/core/ev_handler.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub fn handle_event(
4242
Command::UserInput(InputEvent::Exit) => {
4343
p.exit();
4444
is_exited.store(true, std::sync::atomic::Ordering::SeqCst);
45-
term::cleanup(&mut out, &p.exit_strategy, true)?;
45+
term::cleanup(&mut out, &p.exit_strategy, true, p.persist_alternate)?;
4646
}
4747
Command::UserInput(InputEvent::UpdateUpperMark(mut um)) => {
4848
display::draw_for_change(out, p, &mut um)?;
@@ -274,6 +274,7 @@ pub fn handle_event(
274274
display::write_prompt(out, &p.displayed_prompt, p.rows.try_into().unwrap())?;
275275
}
276276
Command::SetExitStrategy(es) => p.exit_strategy = es,
277+
Command::PersistAlternate(b) => p.persist_alternate = b,
277278
#[cfg(feature = "static_output")]
278279
Command::SetRunNoOverflow(val) => p.run_no_overflow = val,
279280
#[cfg(feature = "search")]
@@ -475,6 +476,26 @@ mod tests {
475476
assert_eq!(ps.exit_strategy, ExitStrategy::PagerQuit);
476477
}
477478

479+
#[test]
480+
fn set_persist_screen() {
481+
let mut ps = PagerState::new().unwrap();
482+
let ev = Command::PersistAlternate(true);
483+
let mut out = Vec::new();
484+
let mut command_queue = CommandQueue::new_zero();
485+
486+
handle_event(
487+
ev,
488+
&mut out,
489+
&mut ps,
490+
&mut command_queue,
491+
&Arc::new(AtomicBool::new(false)),
492+
#[cfg(feature = "search")]
493+
&UIA,
494+
)
495+
.unwrap();
496+
assert_eq!(ps.persist_alternate, true);
497+
}
498+
478499
#[test]
479500
fn add_exit_callback() {
480501
let mut ps = PagerState::new().unwrap();

src/core/init.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ pub fn init_core(pager: &Pager, rm: RunMode) -> std::result::Result<(), MinusErr
133133
stdout(),
134134
&crate::ExitStrategy::PagerQuit,
135135
true,
136+
false,
136137
));
137138
panic_hook(pinfo);
138139
}));
@@ -169,7 +170,7 @@ pub fn init_core(pager: &Pager, rm: RunMode) -> std::result::Result<(), MinusErr
169170
let mut rm = RUNMODE.lock();
170171
*rm = RunMode::Uninitialized;
171172
drop(rm);
172-
term::cleanup(out.as_ref(), &crate::ExitStrategy::PagerQuit, true)?;
173+
term::cleanup(out.as_ref(), &crate::ExitStrategy::PagerQuit, true, false)?;
173174
}
174175
res
175176
});
@@ -188,7 +189,12 @@ pub fn init_core(pager: &Pager, rm: RunMode) -> std::result::Result<(), MinusErr
188189
let mut rm = RUNMODE.lock();
189190
*rm = RunMode::Uninitialized;
190191
drop(rm);
191-
term::cleanup(out_copy.as_ref(), &crate::ExitStrategy::PagerQuit, true)?;
192+
term::cleanup(
193+
out_copy.as_ref(),
194+
&crate::ExitStrategy::PagerQuit,
195+
true,
196+
false,
197+
)?;
192198
}
193199
res
194200
});

src/core/utils/term.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,22 @@ pub fn cleanup(
6060
mut out: impl io::Write,
6161
es: &crate::ExitStrategy,
6262
cleanup_screen: bool,
63+
persist_screen: bool,
6364
) -> std::result::Result<(), CleanupError> {
6465
if cleanup_screen {
6566
// Reverse order of setup.
6667
execute!(out, cursor::Show).map_err(|e| CleanupError::ShowCursor(e.into()))?;
6768
terminal::disable_raw_mode().map_err(|e| CleanupError::DisableRawMode(e.into()))?;
6869
execute!(out, event::DisableMouseCapture)
6970
.map_err(|e| CleanupError::DisableMouseCapture(e.into()))?;
70-
execute!(out, terminal::LeaveAlternateScreen)
71-
.map_err(|e| CleanupError::LeaveAlternateScreen(e.into()))?;
71+
if !persist_screen {
72+
execute!(out, terminal::LeaveAlternateScreen)
73+
.map_err(|e| CleanupError::LeaveAlternateScreen(e.into()))?;
74+
} else {
75+
// Clear out the pager line, it's not something you'd want to keep
76+
queue!(out, Clear(terminal::ClearType::CurrentLine)).unwrap();
77+
out.flush().unwrap();
78+
}
7279
}
7380

7481
if *es == crate::ExitStrategy::ProcessQuit {

src/pager.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,15 @@ impl Pager {
186186
Ok(self.tx.send(Command::SetExitStrategy(es))?)
187187
}
188188

189+
/// Set if minus persists the alternate screen buffer on exit.
190+
///
191+
/// This controls how the pager will behave with regards to clearing the screen when
192+
/// the user presses `q` or `Ctrl+C'. If it is set, instead of clearing the screen
193+
/// when exited, it will continue to show.
194+
pub fn persist_alternate_screen(&self, b: bool) -> Result<(), MinusError> {
195+
Ok(self.tx.send(Command::PersistAlternate(b))?)
196+
}
197+
189198
/// Set whether to display pager if there's less data than
190199
/// available screen height
191200
///

src/state.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ pub struct PagerState {
143143
/// The behaviour to do when user quits the program using `q` or `Ctrl+C`
144144
/// See [`ExitStrategy`] for available options
145145
pub(crate) exit_strategy: ExitStrategy,
146+
/// The behaviour to do when user quits the program using `q` or `Ctrl+C`
147+
/// See [persist_alternate_screen](crate::pager::Pager::persist_alternate_screen) for more info.
148+
pub(crate) persist_alternate: bool,
146149
/// The prompt that should be displayed to the user, formatted with the
147150
/// current search index and number of matches (if the search feature is enabled),
148151
/// and the current numbers inputted to scroll
@@ -194,6 +197,7 @@ impl PagerState {
194197
prompt,
195198
running: &minus_core::RUNMODE,
196199
exit_strategy: ExitStrategy::ProcessQuit,
200+
persist_alternate: false,
197201
input_classifier: Box::<HashedEventRegister<RandomState>>::default(),
198202
exit_callbacks: Vec::with_capacity(5),
199203
message: None,

0 commit comments

Comments
 (0)