Cargo.lock 🔗
@@ -17135,7 +17135,6 @@ dependencies = [
"serde_json",
"settings",
"shellexpand 2.1.2",
- "smol",
"task",
"terminal",
"theme",
Lukas Wirth created
Release Notes:
- N/A *or* Added/Fixed/Improved ...
Cargo.lock | 1
crates/editor/src/blink_manager.rs | 19 ++
crates/editor/src/editor.rs | 8 +
crates/terminal_view/Cargo.toml | 1
crates/terminal_view/src/terminal_view.rs | 137 ++++++++++++------------
5 files changed, 89 insertions(+), 77 deletions(-)
@@ -17135,7 +17135,6 @@ dependencies = [
"serde_json",
"settings",
"shellexpand 2.1.2",
- "smol",
"task",
"terminal",
"theme",
@@ -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>) -> Self {
+ pub fn new(
+ blink_interval: Duration,
+ blink_enabled_in_settings: fn(&App) -> bool,
+ cx: &mut Context<Self>,
+ ) -> Self {
// Make sure we blink the cursors if the setting is re-enabled
cx.observe_global::<SettingsStore>(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<Self>) {
- 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<Self>) {
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>) {
self.visible = false;
self.enabled = false;
@@ -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);
}
@@ -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
@@ -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<ContextMenu>, gpui::Point<Pixels>, Subscription)>,
cursor_shape: CursorShape,
- blink_state: bool,
+ blink_manager: Entity<BlinkManager>,
mode: TerminalMode,
blinking_terminal_enabled: bool,
cwd_serialized: bool,
- blinking_paused: bool,
- blink_epoch: usize,
hover: Option<HoverTarget>,
hover_tooltip_update: Task<()>,
workspace_id: Option<WorkspaceId>,
@@ -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::<SettingsStore>(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::<SettingsStore>(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<Self>) -> 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<Self>) {
- 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>) {
- 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>) {
+ self.blink_manager.update(cx, BlinkManager::pause_blinking);
}
pub fn terminal(&self) -> &Entity<Terminal> {
@@ -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<Self>,
- ) {
- 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>) {
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<Self>) {
+ fn focus_out(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
+ self.blink_manager.update(cx, BlinkManager::disable);
self.terminal.update(cx, |terminal, _| {
terminal.focus_out();
terminal.set_cursor_shape(CursorShape::Hollow);