Always synchronize terminal before rendering it (#4114)

Antonio Scandurra created

Previously, we were trying not to synchronize the terminal too often
because there could be multiple layout/paint calls prior to rendering a
frame.

Now that we perform a single render pass per frame, we can just
synchronize the terminal state. Not doing so could make it seem like
we're dropping frames.

Release Notes:

- Improved terminal rendering performance.

Change summary

crates/terminal/src/terminal.rs              | 35 +--------------------
crates/terminal_view/src/terminal_element.rs |  2 
2 files changed, 4 insertions(+), 33 deletions(-)

Detailed changes

crates/terminal/src/terminal.rs 🔗

@@ -47,7 +47,7 @@ use std::{
     os::unix::prelude::AsRawFd,
     path::PathBuf,
     sync::Arc,
-    time::{Duration, Instant},
+    time::Duration,
 };
 use thiserror::Error;
 
@@ -385,8 +385,6 @@ impl TerminalBuilder {
             last_content: Default::default(),
             last_mouse: None,
             matches: Vec::new(),
-            last_synced: Instant::now(),
-            sync_task: None,
             selection_head: None,
             shell_fd: fd as u32,
             shell_pid,
@@ -542,8 +540,6 @@ pub struct Terminal {
     last_mouse_position: Option<Point<Pixels>>,
     pub matches: Vec<RangeInclusive<AlacPoint>>,
     pub last_content: TerminalContent,
-    last_synced: Instant,
-    sync_task: Option<Task<()>>,
     pub selection_head: Option<AlacPoint>,
     pub breadcrumb_text: String,
     shell_pid: u32,
@@ -977,40 +973,15 @@ impl Terminal {
         self.input(paste_text);
     }
 
-    pub fn try_sync(&mut self, cx: &mut ModelContext<Self>) {
+    pub fn sync(&mut self, cx: &mut ModelContext<Self>) {
         let term = self.term.clone();
-
-        let mut terminal = if let Some(term) = term.try_lock_unfair() {
-            term
-        } else if self.last_synced.elapsed().as_secs_f32() > 0.25 {
-            term.lock_unfair() // It's been too long, force block
-        } else if let None = self.sync_task {
-            //Skip this frame
-            let delay = cx.background_executor().timer(Duration::from_millis(16));
-            self.sync_task = Some(cx.spawn(|weak_handle, mut cx| async move {
-                delay.await;
-                if let Some(handle) = weak_handle.upgrade() {
-                    handle
-                        .update(&mut cx, |terminal, cx| {
-                            terminal.sync_task.take();
-                            cx.notify();
-                        })
-                        .ok();
-                }
-            }));
-            return;
-        } else {
-            //No lock and delayed rendering already scheduled, nothing to do
-            return;
-        };
-
+        let mut terminal = term.lock_unfair();
         //Note that the ordering of events matters for event processing
         while let Some(e) = self.events.pop_front() {
             self.process_terminal_event(&e, &mut terminal, cx)
         }
 
         self.last_content = Self::make_content(&terminal, &self.last_content);
-        self.last_synced = Instant::now();
     }
 
     fn make_content(term: &Term<ZedListener>, last_content: &TerminalContent) -> TerminalContent {

crates/terminal_view/src/terminal_element.rs 🔗

@@ -446,7 +446,7 @@ impl TerminalElement {
 
         let last_hovered_word = self.terminal.update(cx, |terminal, cx| {
             terminal.set_size(dimensions);
-            terminal.try_sync(cx);
+            terminal.sync(cx);
             if self.can_navigate_to_selected_word && terminal.can_navigate_to_selected_word() {
                 terminal.last_content.last_hovered_word.clone()
             } else {