Skip to content

Commit

Permalink
feat: Smooth cursor blink animation option (#2421)
Browse files Browse the repository at this point in the history
  • Loading branch information
agraven committed Mar 22, 2024
1 parent db9cf6e commit a11c8e3
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 4 deletions.
29 changes: 28 additions & 1 deletion src/renderer/cursor_renderer/blink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum BlinkState {

pub struct BlinkStatus {
state: BlinkState,
/// When the cursor should change to the next [`BlinkState`]
transition_time: Instant,
current_cursor: Option<Cursor>,
}
Expand Down Expand Up @@ -62,7 +63,7 @@ impl BlinkStatus {
let current_cursor = self.current_cursor.as_ref().unwrap();

if is_static(current_cursor) {
self.state = BlinkState::On;
self.state = BlinkState::Waiting;
ShouldRender::Wait
} else {
if self.transition_time <= now {
Expand All @@ -82,6 +83,32 @@ impl BlinkStatus {
}
}

/// Calculate the opacity the cursor should be drawn with when smooth cursor blink is enabled.
/// `0.0` is fully transparent, `1.0` is fully opaque.
pub fn opacity(&self) -> f32 {
let now = Instant::now();
if self.state == BlinkState::Waiting {
return 1.0;
}
let total = self.get_delay().as_secs_f32();
let remaining = (self.transition_time - now).as_secs_f32();
match self.state {
BlinkState::Waiting => 1.0,
BlinkState::On => (remaining / total).clamp(0.0, 1.0),
BlinkState::Off => (1.0 - remaining / total).clamp(0.0, 1.0),
}
}

/// Whether or not the cursor is in a state that should be animated (only applicable when
/// smooth blink is enabled).
pub fn should_animate(&self) -> bool {
match self.state {
BlinkState::Waiting => false,
BlinkState::On | BlinkState::Off => true,
}
}

/// Whether or not the cursor should be drawn (only applicable when smooth blink is disabled).
pub fn should_render(&self) -> bool {
match self.state {
BlinkState::Off => false,
Expand Down
17 changes: 14 additions & 3 deletions src/renderer/cursor_renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct CursorSettings {
animate_command_line: bool,
trail_size: f32,
unfocused_outline_width: f32,
smooth_blink: bool,

vfx_mode: cursor_vfx::VfxMode,
vfx_opacity: f32,
Expand All @@ -53,6 +54,7 @@ impl Default for CursorSettings {
animate_command_line: true,
trail_size: 0.7,
unfocused_outline_width: 1.0 / 8.0,
smooth_blink: false,
vfx_mode: cursor_vfx::VfxMode::Disabled,
vfx_opacity: 200.0,
vfx_particle_lifetime: 1.2,
Expand Down Expand Up @@ -286,8 +288,13 @@ impl CursorRenderer {

pub fn draw(&mut self, grid_renderer: &mut GridRenderer, canvas: &Canvas) {
tracy_zone!("cursor_draw");
let render = self.blink_status.should_render();
let settings = SETTINGS.get::<CursorSettings>();
let render = self.blink_status.should_render() || settings.smooth_blink;
let opacity = match settings.smooth_blink {
true => self.blink_status.opacity(),
false => 1.0,
};
let alpha = self.cursor.alpha() as f32;

let mut paint = Paint::new(skia_safe::colors::WHITE, None);
paint.set_anti_alias(settings.antialiasing);
Expand All @@ -302,7 +309,7 @@ impl CursorRenderer {
.cursor
.background(&grid_renderer.default_style.colors)
.to_color()
.with_a(self.cursor.alpha());
.with_a((opacity * alpha) as u8);
paint.set_color(background_color);

let path = if self.window_has_focus || self.cursor.shape != CursorShape::Block {
Expand All @@ -317,7 +324,7 @@ impl CursorRenderer {
.cursor
.foreground(&grid_renderer.default_style.colors)
.to_color()
.with_a(self.cursor.alpha());
.with_a((opacity * alpha) as u8);
paint.set_color(foreground_color);

canvas.save();
Expand Down Expand Up @@ -422,6 +429,10 @@ impl CursorRenderer {
animating |= vfx_animating;
}

let blink_animating = settings.smooth_blink && self.blink_status.should_animate();

animating |= blink_animating;

if !animating {
self.previous_editor_mode = current_mode.clone();
}
Expand Down
18 changes: 18 additions & 0 deletions website/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,24 @@ If the value is \<=0 then the cursor will be invisible. This setting takes effec
window is unfocused, at which time a block cursor will be rendered as an outline instead of as a
full rectangle.

#### Animate cursor blink

VimScript:

```vim
let g:neovide_cursor_smooth_blink = v:false
```

Lua:

```lua
vim.g.neovide_cursor_smooth_blink = false
```

If enabled, the cursor will smoothly animate the transition between the cursor's on and off state.
The built in `guicursor` neovim option needs to be configured to enable blinking by having a value
set for both `blinkoff`, `blinkon` and `blinkwait` for this setting to apply.

### Cursor Particles

There are a number of vfx modes you can enable which produce particles behind the cursor. These are
Expand Down

0 comments on commit a11c8e3

Please sign in to comment.