From 8605ed15473c4d7faa7381fbf91edb7d06bd8754 Mon Sep 17 00:00:00 2001 From: Priec Date: Sat, 2 Aug 2025 22:08:43 +0200 Subject: [PATCH] fixing issues in the edit/normal mode --- canvas/src/editor.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/canvas/src/editor.rs b/canvas/src/editor.rs index 5fe3f1e..614ccce 100644 --- a/canvas/src/editor.rs +++ b/canvas/src/editor.rs @@ -3,6 +3,8 @@ #[cfg(feature = "cursor-style")] use crate::canvas::CursorManager; +#[cfg(feature = "cursor-style")] +use crossterm; use anyhow::Result; use crate::canvas::state::EditorState; @@ -162,6 +164,18 @@ impl FormEditor { #[cfg(feature = "cursor-style")] if old_mode != mode { let _ = crate::canvas::CursorManager::update_for_mode(mode); + + // IMMEDIATELY update terminal cursor position for the new mode + // This prevents flicker by ensuring position and style change atomically + if let Ok((x, y)) = crossterm::cursor::position() { + let display_pos = self.display_cursor_position(); + let current_text = self.current_text(); + let adjusted_x = x.saturating_sub(current_text.len() as u16) + display_pos as u16; + let _ = crossterm::execute!( + std::io::stdout(), + crossterm::cursor::MoveTo(adjusted_x, y) + ); + } } } @@ -459,7 +473,19 @@ impl FormEditor { } /// Exit edit mode to read-only mode (vim Escape) + // TODO this is still flickering, I have no clue how to fix it pub fn exit_edit_mode(&mut self) { + // Adjust cursor position when transitioning from edit to normal mode + let current_text = self.current_text(); + if !current_text.is_empty() { + // In normal mode, cursor must be ON a character, not after the last one + let max_normal_pos = current_text.len().saturating_sub(1); + if self.ui_state.cursor_pos > max_normal_pos { + self.ui_state.cursor_pos = max_normal_pos; + self.ui_state.ideal_cursor_column = self.ui_state.cursor_pos; + } + } + self.set_mode(AppMode::ReadOnly); // Deactivate autocomplete when exiting edit mode self.ui_state.deactivate_autocomplete(); @@ -540,6 +566,26 @@ impl FormEditor { self.ui_state.ideal_cursor_column = clamped_pos; } + /// Get cursor position for display (respects mode-specific positioning rules) + pub fn display_cursor_position(&self) -> usize { + let current_text = self.current_text(); + + match self.ui_state.current_mode { + AppMode::Edit => { + // Edit mode: cursor can be past end of text + self.ui_state.cursor_pos.min(current_text.len()) + } + _ => { + // Normal/other modes: cursor must be on a character + if current_text.is_empty() { + 0 + } else { + self.ui_state.cursor_pos.min(current_text.len().saturating_sub(1)) + } + } + } + } + /// Cleanup cursor style (call this when shutting down) pub fn cleanup_cursor(&self) -> std::io::Result<()> { #[cfg(feature = "cursor-style")]