Skip to content

Commit 9950972

Browse files
committed
Avoid "flashes" while resizing the terminal
We would previously "flash" the screen with the terminal's configured background color between a call to `Backend::clear` and the following render. This was because the `Backend::clear` command was not "batched" in with the render (i.e. synchronized output rendering). We can enable synchronized outputs in the `Backend::clear` callback to batch the clear together with the following render to avoid the flash.
1 parent a06f6d5 commit 9950972

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

helix-tui/src/backend/termina.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub struct TerminaBackend {
9090
config: Config,
9191
capabilities: Capabilities,
9292
reset_cursor_command: String,
93+
is_synchronized_output_set: bool,
9394
}
9495

9596
impl TerminaBackend {
@@ -103,6 +104,7 @@ impl TerminaBackend {
103104
config,
104105
capabilities,
105106
reset_cursor_command,
107+
is_synchronized_output_set: false,
106108
})
107109
}
108110

@@ -297,6 +299,28 @@ impl TerminaBackend {
297299

298300
Ok(())
299301
}
302+
303+
// See <https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036>.
304+
// Synchronized output sequences tell the terminal when we are "starting to render" and
305+
// stopping, enabling to make better choices about when it draws a frame. This avoids all
306+
// kinds of ugly visual artifacts like tearing and flashing (i.e. the background color
307+
// after clearing the terminal).
308+
309+
fn start_synchronized_render(&mut self) -> io::Result<()> {
310+
if self.capabilities.synchronized_output && !self.is_synchronized_output_set {
311+
write!(self.terminal, "{}", decset!(SynchronizedOutput))?;
312+
self.is_synchronized_output_set = true;
313+
}
314+
Ok(())
315+
}
316+
317+
fn end_sychronized_render(&mut self) -> io::Result<()> {
318+
if self.is_synchronized_output_set {
319+
write!(self.terminal, "{}", decreset!(SynchronizedOutput))?;
320+
self.is_synchronized_output_set = false;
321+
}
322+
Ok(())
323+
}
300324
}
301325

302326
impl Backend for TerminaBackend {
@@ -352,9 +376,7 @@ impl Backend for TerminaBackend {
352376
where
353377
I: Iterator<Item = (u16, u16, &'a Cell)>,
354378
{
355-
if self.capabilities.synchronized_output {
356-
write!(self.terminal, "{}", decset!(SynchronizedOutput))?;
357-
}
379+
self.start_synchronized_render()?;
358380

359381
let mut fg = Color::Reset;
360382
let mut bg = Color::Reset;
@@ -430,9 +452,7 @@ impl Backend for TerminaBackend {
430452

431453
write!(self.terminal, "{}", Csi::Sgr(csi::Sgr::Reset))?;
432454

433-
if self.capabilities.synchronized_output {
434-
write!(self.terminal, "{}", decreset!(SynchronizedOutput))?;
435-
}
455+
self.end_sychronized_render()?;
436456

437457
Ok(())
438458
}
@@ -489,6 +509,7 @@ impl Backend for TerminaBackend {
489509
}
490510

491511
fn clear(&mut self) -> io::Result<()> {
512+
self.start_synchronized_render()?;
492513
write!(
493514
self.terminal,
494515
"{}",

0 commit comments

Comments
 (0)