diff --git a/Cargo.lock b/Cargo.lock index bea1424b704eb9e3bc07ddfa2e7b6de817687a72..e41e973041bfe99dec6258e910e1108a842c0748 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17135,7 +17135,6 @@ dependencies = [ "serde_json", "settings", "shellexpand 2.1.2", - "smol", "task", "terminal", "theme", diff --git a/crates/editor/src/blink_manager.rs b/crates/editor/src/blink_manager.rs index 9c2b911f1b068d5d8cc14c3875af08033f34bc66..d99cf6a7d59d40383e572f4638b17edbf3d0da53 100644 --- a/crates/editor/src/blink_manager.rs +++ b/crates/editor/src/blink_manager.rs @@ -1,20 +1,28 @@ -use crate::EditorSettings; use gpui::Context; -use settings::Settings; use settings::SettingsStore; use smol::Timer; use std::time::Duration; +use ui::App; pub struct BlinkManager { blink_interval: Duration, blink_epoch: usize, + /// Whether the blinking is paused. blinking_paused: bool, + /// Whether the cursor should be visibly rendered or not. visible: bool, + /// Whether the blinking currently enabled. enabled: bool, + /// Whether the blinking is enabled in the settings. + blink_enabled_in_settings: fn(&App) -> bool, } impl BlinkManager { - pub fn new(blink_interval: Duration, cx: &mut Context) -> Self { + pub fn new( + blink_interval: Duration, + blink_enabled_in_settings: fn(&App) -> bool, + cx: &mut Context, + ) -> Self { // Make sure we blink the cursors if the setting is re-enabled cx.observe_global::(move |this, cx| { this.blink_cursors(this.blink_epoch, cx) @@ -27,6 +35,7 @@ impl BlinkManager { blinking_paused: false, visible: true, enabled: false, + blink_enabled_in_settings, } } @@ -55,7 +64,7 @@ impl BlinkManager { } fn blink_cursors(&mut self, epoch: usize, cx: &mut Context) { - if EditorSettings::get_global(cx).cursor_blink { + if (self.blink_enabled_in_settings)(cx) { if epoch == self.blink_epoch && self.enabled && !self.blinking_paused { self.visible = !self.visible; cx.notify(); @@ -83,6 +92,7 @@ impl BlinkManager { } } + /// Enable the blinking of the cursor. pub fn enable(&mut self, cx: &mut Context) { if self.enabled { return; @@ -95,6 +105,7 @@ impl BlinkManager { self.blink_cursors(self.blink_epoch, cx); } + /// Disable the blinking of the cursor. pub fn disable(&mut self, _cx: &mut Context) { self.visible = false; self.enabled = false; diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index d4c09e06cbe2349ec759f0546049c462bf95b0a8..e8d0011a98d4126f6baf542589145c9d1ddc8dda 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -12,7 +12,7 @@ //! //! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior. pub mod actions; -mod blink_manager; +pub mod blink_manager; mod bracket_colorization; mod clangd_ext; pub mod code_context_menus; @@ -1888,7 +1888,11 @@ impl Editor { let selections = SelectionsCollection::new(); let blink_manager = cx.new(|cx| { - let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx); + let mut blink_manager = BlinkManager::new( + CURSOR_BLINK_INTERVAL, + |cx| EditorSettings::get_global(cx).cursor_blink, + cx, + ); if is_minimap { blink_manager.disable(cx); } diff --git a/crates/terminal_view/Cargo.toml b/crates/terminal_view/Cargo.toml index 1800562e2fd262d040ef957b402cc650681956a5..eadd00bcbbd7a5469638c2b85d2eb4f1a65b9475 100644 --- a/crates/terminal_view/Cargo.toml +++ b/crates/terminal_view/Cargo.toml @@ -39,7 +39,6 @@ serde.workspace = true serde_json.workspace = true settings.workspace = true shellexpand.workspace = true -smol.workspace = true terminal.workspace = true theme.workspace = true ui.workspace = true diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 66e6c605f9b560dc36db3dde16e84c2ee8c0c5b5..7c8bda83be864353c35b0317efc8599456dca6e5 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -7,7 +7,7 @@ mod terminal_slash_command; pub mod terminal_tab_tooltip; use assistant_slash_command::SlashCommandRegistry; -use editor::{EditorSettings, actions::SelectAll}; +use editor::{EditorSettings, actions::SelectAll, blink_manager::BlinkManager}; use gpui::{ Action, AnyElement, App, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, KeyContext, KeyDownEvent, Keystroke, MouseButton, MouseDownEvent, Pixels, Render, @@ -51,7 +51,6 @@ use workspace::{ use serde::Deserialize; use settings::{Settings, SettingsStore, TerminalBlink, WorkingDirectory}; -use smol::Timer; use zed_actions::assistant::InlineAssist; use std::{ @@ -126,12 +125,10 @@ pub struct TerminalView { has_bell: bool, context_menu: Option<(Entity, gpui::Point, Subscription)>, cursor_shape: CursorShape, - blink_state: bool, + blink_manager: Entity, mode: TerminalMode, blinking_terminal_enabled: bool, cwd_serialized: bool, - blinking_paused: bool, - blink_epoch: usize, hover: Option, hover_tooltip_update: Task<()>, workspace_id: Option, @@ -237,6 +234,25 @@ impl TerminalView { let scroll_handle = TerminalScrollHandle::new(terminal.read(cx)); + let blink_manager = cx.new(|cx| { + BlinkManager::new( + CURSOR_BLINK_INTERVAL, + |cx| { + !matches!( + TerminalSettings::get_global(cx).blinking, + TerminalBlink::Off + ) + }, + cx, + ) + }); + + let _subscriptions = vec![ + focus_in, + focus_out, + cx.observe(&blink_manager, |_, _, cx| cx.notify()), + cx.observe_global::(Self::settings_changed), + ]; Self { terminal, workspace: workspace_handle, @@ -245,10 +261,8 @@ impl TerminalView { focus_handle, context_menu: None, cursor_shape, - blink_state: true, + blink_manager, blinking_terminal_enabled: false, - blinking_paused: false, - blink_epoch: 0, hover: None, hover_tooltip_update: Task::ready(()), mode: TerminalMode::Standalone, @@ -259,11 +273,7 @@ impl TerminalView { scroll_handle, cwd_serialized: false, ime_state: None, - _subscriptions: vec![ - focus_in, - focus_out, - cx.observe_global::(Self::settings_changed), - ], + _subscriptions, _terminal_subscriptions: terminal_subscriptions, } } @@ -424,6 +434,11 @@ impl TerminalView { let breadcrumb_visibility_changed = self.show_breadcrumbs != settings.toolbar.breadcrumbs; self.show_breadcrumbs = settings.toolbar.breadcrumbs; + let should_blink = match settings.blinking { + TerminalBlink::Off => false, + TerminalBlink::On => true, + TerminalBlink::TerminalControlled => self.blinking_terminal_enabled, + }; let new_cursor_shape = settings.cursor_shape; let old_cursor_shape = self.cursor_shape; if old_cursor_shape != new_cursor_shape { @@ -433,6 +448,15 @@ impl TerminalView { }); } + self.blink_manager.update( + cx, + if should_blink { + BlinkManager::enable + } else { + BlinkManager::disable + }, + ); + if breadcrumb_visibility_changed { cx.emit(ItemEvent::UpdateBreadcrumbs); } @@ -610,9 +634,8 @@ impl TerminalView { } pub fn should_show_cursor(&self, focused: bool, cx: &mut Context) -> bool { - //Don't blink the cursor when not focused, blinking is disabled, or paused + // Always show cursor when not focused or in special modes if !focused - || self.blinking_paused || self .terminal .read(cx) @@ -623,45 +646,17 @@ impl TerminalView { return true; } + // When focused, check blinking settings and blink manager state match TerminalSettings::get_global(cx).blinking { - //If the user requested to never blink, don't blink it. TerminalBlink::Off => true, - //If the terminal is controlling it, check terminal mode - TerminalBlink::TerminalControlled => { - !self.blinking_terminal_enabled || self.blink_state + TerminalBlink::On | TerminalBlink::TerminalControlled => { + self.blink_manager.read(cx).visible() } - TerminalBlink::On => self.blink_state, - } - } - - fn blink_cursors(&mut self, epoch: usize, window: &mut Window, cx: &mut Context) { - if epoch == self.blink_epoch && !self.blinking_paused { - self.blink_state = !self.blink_state; - cx.notify(); - - let epoch = self.next_blink_epoch(); - cx.spawn_in(window, async move |this, cx| { - Timer::after(CURSOR_BLINK_INTERVAL).await; - this.update_in(cx, |this, window, cx| this.blink_cursors(epoch, window, cx)) - .ok(); - }) - .detach(); } } - pub fn pause_cursor_blinking(&mut self, window: &mut Window, cx: &mut Context) { - self.blink_state = true; - cx.notify(); - - let epoch = self.next_blink_epoch(); - cx.spawn_in(window, async move |this, cx| { - Timer::after(CURSOR_BLINK_INTERVAL).await; - this.update_in(cx, |this, window, cx| { - this.resume_cursor_blinking(epoch, window, cx) - }) - .ok(); - }) - .detach(); + pub fn pause_cursor_blinking(&mut self, _window: &mut Window, cx: &mut Context) { + self.blink_manager.update(cx, BlinkManager::pause_blinking); } pub fn terminal(&self) -> &Entity { @@ -685,23 +680,6 @@ impl TerminalView { cx.notify(); } - fn next_blink_epoch(&mut self) -> usize { - self.blink_epoch += 1; - self.blink_epoch - } - - fn resume_cursor_blinking( - &mut self, - epoch: usize, - window: &mut Window, - cx: &mut Context, - ) { - if epoch == self.blink_epoch { - self.blinking_paused = false; - self.blink_cursors(epoch, window, cx); - } - } - ///Attempt to paste the clipboard into the terminal fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context) { self.terminal.update(cx, |term, _| term.copy(None)); @@ -893,11 +871,21 @@ fn subscribe_for_terminal_events( } Event::BlinkChanged(blinking) => { + terminal_view.blinking_terminal_enabled = *blinking; + + // If in terminal-controlled mode and focused, update blink manager if matches!( TerminalSettings::get_global(cx).blinking, TerminalBlink::TerminalControlled - ) { - terminal_view.blinking_terminal_enabled = *blinking; + ) && terminal_view.focus_handle.is_focused(window) + { + terminal_view.blink_manager.update(cx, |manager, cx| { + if *blinking { + manager.enable(cx); + } else { + manager.disable(cx); + } + }); } } @@ -1023,12 +1011,23 @@ impl TerminalView { terminal.set_cursor_shape(self.cursor_shape); terminal.focus_in(); }); - self.blink_cursors(self.blink_epoch, window, cx); + + let should_blink = match TerminalSettings::get_global(cx).blinking { + TerminalBlink::Off => false, + TerminalBlink::On => true, + TerminalBlink::TerminalControlled => self.blinking_terminal_enabled, + }; + + if should_blink { + self.blink_manager.update(cx, BlinkManager::enable); + } + window.invalidate_character_coordinates(); cx.notify(); } - fn focus_out(&mut self, _: &mut Window, cx: &mut Context) { + fn focus_out(&mut self, _window: &mut Window, cx: &mut Context) { + self.blink_manager.update(cx, BlinkManager::disable); self.terminal.update(cx, |terminal, _| { terminal.focus_out(); terminal.set_cursor_shape(CursorShape::Hollow);