mirror of
https://github.com/neovide/neovide.git
synced 2026-09-10 07:16:25 -04:00
fix: track reasonable cmdline modes and reset springs on immediate cursor moves (#3484)
the cursor setting neovide_cursor_animate_command_line was broken see https://github.com/neovide/neovide/discussions/3180 first, neovim has three actual editing modes: - cmdline_normal - cmdline_insert - cmdline_replace - cmdline_hover (ignored, mouse shape state, not editing mode) secondly, the immediate movement wasn't actually immediate. we snapped the cursor position, but left the corner springs alive, so the next frame resumed animating and produced the trail we were supposed to suppress. we basically now reset the spring state when movement is forced immediate. there is also a ui2 incompatibility that we fix. (experimental) with ui2, leaving the cmdline is not a single clean mode transition. neovim leaves MODE_CMDLINE first, then ui2 redraws the cursor in its cmdline float one more time before the cursor returns to the real editing window. A plain previous_mode/current_mode check misses that last hop. we fix that by tracking a small cmdline cursor context in the renderer, so the final ui2 exit hop is still treated as part of the cmdline transition.
This commit is contained in:
parent
8355b0c985
commit
99a62e5ab5
|
|
@ -601,7 +601,7 @@ fn parse_mode_change(mode_change_arguments: Vec<Value>) -> Result<RedrawEvent> {
|
|||
"insert" => EditorMode::Insert,
|
||||
"visual" => EditorMode::Visual,
|
||||
"replace" => EditorMode::Replace,
|
||||
"cmdline_normal" => EditorMode::CmdLine,
|
||||
"cmdline_normal" | "cmdline_insert" | "cmdline_replace" => EditorMode::CmdLine,
|
||||
_ => EditorMode::Unknown(mode_name),
|
||||
},
|
||||
mode_index: parse_u64(mode_index)?,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use winit::event_loop::EventLoopProxy;
|
|||
use winit::window::Theme;
|
||||
|
||||
use crate::{
|
||||
bridge::{GridLineCell, GuiOption, NeovimHandler, RedrawEvent, WindowAnchor},
|
||||
bridge::{EditorMode, GridLineCell, GuiOption, NeovimHandler, RedrawEvent, WindowAnchor},
|
||||
clipboard::ClipboardHandle,
|
||||
profiling::{tracy_named_frame, tracy_zone},
|
||||
renderer::{DrawCommand, WindowDrawCommand, rendered_window::BASE_GRID_ID},
|
||||
|
|
@ -36,8 +36,6 @@ pub use style::{Colors, Style, UnderlineStyle};
|
|||
pub use window::*;
|
||||
|
||||
use intro::{IntroMessageExtender, IntroProcessing};
|
||||
|
||||
const MODE_CMDLINE: u64 = 4;
|
||||
pub const MSG_ZINDEX: u64 = 200; // See the documenation for nvim_open_win
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
|
@ -116,6 +114,7 @@ pub struct Editor {
|
|||
pub mode_list: Vec<CursorMode>,
|
||||
pub draw_command_batcher: DrawCommandBatcher,
|
||||
pub current_mode_index: Option<u64>,
|
||||
current_mode: EditorMode,
|
||||
pub ui_ready: bool,
|
||||
event_loop_proxy: EventLoopProxy<EventPayload>,
|
||||
route_id: RouteId,
|
||||
|
|
@ -158,6 +157,7 @@ impl Editor {
|
|||
mode_list: Vec::new(),
|
||||
draw_command_batcher: DrawCommandBatcher::new(),
|
||||
current_mode_index: None,
|
||||
current_mode: EditorMode::Normal,
|
||||
ui_ready: false,
|
||||
settings,
|
||||
event_loop_proxy,
|
||||
|
|
@ -202,6 +202,7 @@ impl Editor {
|
|||
} else {
|
||||
self.current_mode_index = None
|
||||
}
|
||||
self.current_mode = mode.clone();
|
||||
self.draw_command_batcher.queue(DrawCommand::ModeChanged(mode));
|
||||
}
|
||||
RedrawEvent::MouseOn => {
|
||||
|
|
@ -657,8 +658,7 @@ impl Editor {
|
|||
let already_there = self.cursor.parent_window_id == grid;
|
||||
// This ^ check alone is a bit buggy though, since it fails when the cursor is
|
||||
// technically still in the edit window but "temporarily" at the cmdline. (#1207)
|
||||
let using_cmdline =
|
||||
self.current_mode_index.map(|current| current == MODE_CMDLINE).unwrap_or(false);
|
||||
let using_cmdline = matches!(self.current_mode, EditorMode::CmdLine);
|
||||
|
||||
if !intentional && !already_there && !using_cmdline {
|
||||
trace!(
|
||||
|
|
|
|||
|
|
@ -135,6 +135,8 @@ impl Corner {
|
|||
}
|
||||
|
||||
if immediate_movement {
|
||||
self.animation_x.reset();
|
||||
self.animation_y.reset();
|
||||
self.current_position = corner_destination;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -214,6 +216,38 @@ impl Corner {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum CmdlineCtx {
|
||||
Inactive,
|
||||
Active { window: u64 },
|
||||
Exiting { window: u64 },
|
||||
}
|
||||
|
||||
impl CmdlineCtx {
|
||||
fn active(current_window: u64) -> Self {
|
||||
Self::Active { window: current_window }
|
||||
}
|
||||
|
||||
fn exiting_or_inactive(window: u64, current_window: u64) -> Self {
|
||||
if current_window == window { Self::Exiting { window } } else { Self::Inactive }
|
||||
}
|
||||
|
||||
fn advance(self, current_mode: &EditorMode, current_window: u64) -> Self {
|
||||
let in_cmdline = matches!(current_mode, EditorMode::CmdLine);
|
||||
|
||||
if in_cmdline {
|
||||
return Self::active(current_window);
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::Inactive => Self::Inactive,
|
||||
Self::Active { window } | Self::Exiting { window } => {
|
||||
Self::exiting_or_inactive(window, current_window)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CursorRenderer {
|
||||
pub corners: Vec<Corner>,
|
||||
cursor: Cursor,
|
||||
|
|
@ -221,7 +255,7 @@ pub struct CursorRenderer {
|
|||
blink_status: BlinkStatus,
|
||||
previous_cursor_position: Option<(u64, GridPos<u64>)>,
|
||||
previous_cursor_shape: Option<CursorShape>,
|
||||
previous_editor_mode: EditorMode,
|
||||
cmdline_ctx: CmdlineCtx,
|
||||
cursor_vfxs: Vec<Box<dyn cursor_vfx::CursorVfx>>,
|
||||
previous_vfx_mode: cursor_vfx::VfxModeList,
|
||||
window_has_focus: bool,
|
||||
|
|
@ -239,7 +273,7 @@ impl CursorRenderer {
|
|||
blink_status: BlinkStatus::new(),
|
||||
previous_cursor_position: None,
|
||||
previous_cursor_shape: None,
|
||||
previous_editor_mode: EditorMode::Normal,
|
||||
cmdline_ctx: CmdlineCtx::Inactive,
|
||||
cursor_vfxs: vec![],
|
||||
previous_vfx_mode: cursor_vfx::VfxModeList::default(),
|
||||
window_has_focus: true,
|
||||
|
|
@ -434,8 +468,9 @@ impl CursorRenderer {
|
|||
|
||||
let in_insert_mode = matches!(current_mode, EditorMode::Insert);
|
||||
|
||||
let changed_to_from_cmdline = !matches!(self.previous_editor_mode, EditorMode::CmdLine)
|
||||
^ matches!(current_mode, EditorMode::CmdLine);
|
||||
let next_cmdline_ctx = self.cmdline_ctx.advance(current_mode, self.cursor.parent_window_id);
|
||||
let changed_to_from_cmdline = !matches!(self.cmdline_ctx, CmdlineCtx::Inactive)
|
||||
^ !matches!(next_cmdline_ctx, CmdlineCtx::Inactive);
|
||||
|
||||
let center_destination = self.destination + cursor_dimensions.to_vector() * 0.5;
|
||||
|
||||
|
|
@ -455,7 +490,7 @@ impl CursorRenderer {
|
|||
|
||||
if center_destination != PixelPos::ZERO {
|
||||
let immediate_movement = !settings.animate_in_insert_mode && in_insert_mode
|
||||
|| !settings.animate_command_line && !changed_to_from_cmdline;
|
||||
|| !settings.animate_command_line && changed_to_from_cmdline;
|
||||
if self.jumped {
|
||||
// Caclculate the direction alignment for each corner and generate a sorted list
|
||||
// This way we know which corner is the front and which is the back
|
||||
|
|
@ -522,14 +557,11 @@ impl CursorRenderer {
|
|||
animating |= vfx_animating;
|
||||
}
|
||||
self.jumped = false;
|
||||
self.cmdline_ctx = next_cmdline_ctx;
|
||||
|
||||
let blink_animating = settings.smooth_blink && self.blink_status.should_animate();
|
||||
|
||||
animating |= blink_animating;
|
||||
|
||||
if !animating {
|
||||
self.previous_editor_mode = current_mode.clone();
|
||||
}
|
||||
tracy_plot!("cursor animating", animating as u8 as f64);
|
||||
animating
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue