prod comments in the codebase
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
// src/canvas/actions/mod.rs
|
// src/canvas/actions/mod.rs
|
||||||
|
//! Canvas action definitions and movement utilities
|
||||||
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod movement;
|
pub mod movement;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// src/canvas/actions/movement/char.rs
|
// src/canvas/actions/movement/char.rs
|
||||||
|
//! Character-level cursor movement functions
|
||||||
|
|
||||||
/// Calculate new position when moving left
|
/// Calculate new position when moving left
|
||||||
pub fn move_left(current_pos: usize) -> usize {
|
pub fn move_left(current_pos: usize) -> usize {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// src/canvas/actions/movement/line.rs
|
// src/canvas/actions/movement/line.rs
|
||||||
|
//! Line-level cursor movement and positioning
|
||||||
|
|
||||||
/// Calculate cursor position for line start
|
/// Calculate cursor position for line start
|
||||||
pub fn line_start_position() -> usize {
|
pub fn line_start_position() -> usize {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// src/canvas/actions/movement/mod.rs
|
// src/canvas/actions/movement/mod.rs
|
||||||
|
//! Movement utilities for character, word, and line navigation
|
||||||
|
|
||||||
pub mod word;
|
pub mod word;
|
||||||
pub mod line;
|
pub mod line;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// src/canvas/actions/movement/word.rs
|
// src/canvas/actions/movement/word.rs
|
||||||
// Replace the entire file with this corrected version:
|
//! Word-based cursor movement with vim-like semantics
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
enum CharType {
|
enum CharType {
|
||||||
|
|||||||
@@ -1,79 +1,121 @@
|
|||||||
// src/canvas/actions/types.rs
|
// src/canvas/actions/types.rs
|
||||||
|
//! Core action types and result handling for canvas operations.
|
||||||
|
|
||||||
/// All available canvas actions
|
/// All available canvas actions.
|
||||||
|
///
|
||||||
|
/// This enum lists high-level actions that can be performed on the canvas.
|
||||||
|
/// Consumers can match on variants to implement custom handling or map input
|
||||||
|
/// events to these canonical actions.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum CanvasAction {
|
pub enum CanvasAction {
|
||||||
// Movement actions
|
// Movement actions
|
||||||
|
/// Move the cursor left by one character (or logical unit).
|
||||||
MoveLeft,
|
MoveLeft,
|
||||||
|
/// Move the cursor right by one character (or logical unit).
|
||||||
MoveRight,
|
MoveRight,
|
||||||
|
/// Move the cursor up a visual line/field.
|
||||||
MoveUp,
|
MoveUp,
|
||||||
|
/// Move the cursor down a visual line/field.
|
||||||
MoveDown,
|
MoveDown,
|
||||||
|
|
||||||
// Word movement
|
// Word movement
|
||||||
|
/// Move to the start of the next word.
|
||||||
MoveWordNext,
|
MoveWordNext,
|
||||||
|
/// Move to the start of the previous word.
|
||||||
MoveWordPrev,
|
MoveWordPrev,
|
||||||
|
/// Move to the end of the current/next word.
|
||||||
MoveWordEnd,
|
MoveWordEnd,
|
||||||
|
/// Move to the previous word end (vim `ge`).
|
||||||
MoveWordEndPrev,
|
MoveWordEndPrev,
|
||||||
|
|
||||||
// Line movement
|
// Line movement
|
||||||
|
/// Move to the start of the current line.
|
||||||
MoveLineStart,
|
MoveLineStart,
|
||||||
|
/// Move to the end of the current line.
|
||||||
MoveLineEnd,
|
MoveLineEnd,
|
||||||
|
|
||||||
// Field movement
|
// Field movement
|
||||||
|
/// Move to the next field.
|
||||||
NextField,
|
NextField,
|
||||||
|
/// Move to the previous field.
|
||||||
PrevField,
|
PrevField,
|
||||||
|
/// Move to the first field.
|
||||||
MoveFirstLine,
|
MoveFirstLine,
|
||||||
|
/// Move to the last field.
|
||||||
MoveLastLine,
|
MoveLastLine,
|
||||||
|
|
||||||
// Editing actions
|
// Editing actions
|
||||||
|
/// Insert a character at the cursor.
|
||||||
InsertChar(char),
|
InsertChar(char),
|
||||||
|
/// Delete character before the cursor.
|
||||||
DeleteBackward,
|
DeleteBackward,
|
||||||
|
/// Delete character under/after the cursor.
|
||||||
DeleteForward,
|
DeleteForward,
|
||||||
|
|
||||||
// Suggestions actions
|
// Suggestions actions
|
||||||
TriggerSuggestions,
|
/// Trigger suggestions dropdown (e.g. Tab).
|
||||||
SuggestionUp,
|
TriggerSuggestions,
|
||||||
SuggestionDown,
|
/// Move selection up in suggestions dropdown.
|
||||||
SelectSuggestion,
|
SuggestionUp,
|
||||||
ExitSuggestions,
|
/// Move selection down in suggestions dropdown.
|
||||||
|
SuggestionDown,
|
||||||
|
/// Accept the selected suggestion.
|
||||||
|
SelectSuggestion,
|
||||||
|
/// Exit suggestions UI.
|
||||||
|
ExitSuggestions,
|
||||||
|
|
||||||
// Custom actions
|
// Custom actions
|
||||||
|
/// Custom named action for application-specific behavior.
|
||||||
Custom(String),
|
Custom(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result type for canvas actions
|
/// Result type for canvas actions.
|
||||||
|
///
|
||||||
|
/// Action handlers return an ActionResult to indicate success, user-facing
|
||||||
|
/// messages, or errors. The enum is non-exhaustive to allow extension.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ActionResult {
|
pub enum ActionResult {
|
||||||
|
/// Action completed successfully.
|
||||||
Success,
|
Success,
|
||||||
|
/// Action completed with a user-facing message.
|
||||||
Message(String),
|
Message(String),
|
||||||
|
/// Action was handled by the application with an associated message.
|
||||||
HandledByApp(String),
|
HandledByApp(String),
|
||||||
|
/// Action was handled by a feature with an associated message.
|
||||||
HandledByFeature(String), // Keep for compatibility
|
HandledByFeature(String), // Keep for compatibility
|
||||||
|
/// An error occurred while handling the action.
|
||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionResult {
|
impl ActionResult {
|
||||||
|
/// Convenience constructor for Success.
|
||||||
pub fn success() -> Self {
|
pub fn success() -> Self {
|
||||||
Self::Success
|
Self::Success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience constructor for Message.
|
||||||
pub fn success_with_message(msg: &str) -> Self {
|
pub fn success_with_message(msg: &str) -> Self {
|
||||||
Self::Message(msg.to_string())
|
Self::Message(msg.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience constructor for HandledByApp.
|
||||||
pub fn handled_by_app(msg: &str) -> Self {
|
pub fn handled_by_app(msg: &str) -> Self {
|
||||||
Self::HandledByApp(msg.to_string())
|
Self::HandledByApp(msg.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience constructor for Error.
|
||||||
pub fn error(msg: &str) -> Self {
|
pub fn error(msg: &str) -> Self {
|
||||||
Self::Error(msg.to_string())
|
Self::Error(msg.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true for any variant representing a success-like outcome.
|
||||||
pub fn is_success(&self) -> bool {
|
pub fn is_success(&self) -> bool {
|
||||||
matches!(self, Self::Success | Self::Message(_) | Self::HandledByApp(_) | Self::HandledByFeature(_))
|
matches!(self, Self::Success | Self::Message(_) | Self::HandledByApp(_) | Self::HandledByFeature(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract a message from the result when present.
|
||||||
pub fn message(&self) -> Option<&str> {
|
pub fn message(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
Self::Message(msg) | Self::HandledByApp(msg) | Self::HandledByFeature(msg) | Self::Error(msg) => Some(msg),
|
Self::Message(msg) | Self::HandledByApp(msg) | Self::HandledByFeature(msg) | Self::Error(msg) => Some(msg),
|
||||||
@@ -83,7 +125,7 @@ impl ActionResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CanvasAction {
|
impl CanvasAction {
|
||||||
/// Get a human-readable description of this action
|
/// Get a human-readable description of this action.
|
||||||
pub fn description(&self) -> &'static str {
|
pub fn description(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::MoveLeft => "move left",
|
Self::MoveLeft => "move left",
|
||||||
@@ -112,7 +154,7 @@ impl CanvasAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all movement-related actions
|
/// Get all movement-related actions.
|
||||||
pub fn movement_actions() -> Vec<CanvasAction> {
|
pub fn movement_actions() -> Vec<CanvasAction> {
|
||||||
vec![
|
vec![
|
||||||
Self::MoveLeft,
|
Self::MoveLeft,
|
||||||
@@ -132,7 +174,7 @@ impl CanvasAction {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all editing-related actions
|
/// Get all editing-related actions.
|
||||||
pub fn editing_actions() -> Vec<CanvasAction> {
|
pub fn editing_actions() -> Vec<CanvasAction> {
|
||||||
vec![
|
vec![
|
||||||
Self::InsertChar(' '), // Example char
|
Self::InsertChar(' '), // Example char
|
||||||
@@ -141,7 +183,7 @@ impl CanvasAction {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all suggestions-related actions
|
/// Get all suggestions-related actions.
|
||||||
pub fn suggestions_actions() -> Vec<CanvasAction> {
|
pub fn suggestions_actions() -> Vec<CanvasAction> {
|
||||||
vec![
|
vec![
|
||||||
Self::TriggerSuggestions,
|
Self::TriggerSuggestions,
|
||||||
@@ -152,7 +194,7 @@ impl CanvasAction {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if this action modifies text content
|
/// Check if this action modifies text content.
|
||||||
pub fn is_editing_action(&self) -> bool {
|
pub fn is_editing_action(&self) -> bool {
|
||||||
matches!(self,
|
matches!(self,
|
||||||
Self::InsertChar(_) |
|
Self::InsertChar(_) |
|
||||||
@@ -161,7 +203,7 @@ impl CanvasAction {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if this action moves the cursor
|
/// Check if this action moves the cursor.
|
||||||
pub fn is_movement_action(&self) -> bool {
|
pub fn is_movement_action(&self) -> bool {
|
||||||
matches!(self,
|
matches!(self,
|
||||||
Self::MoveLeft | Self::MoveRight | Self::MoveUp | Self::MoveDown |
|
Self::MoveLeft | Self::MoveRight | Self::MoveUp | Self::MoveDown |
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
// src/canvas/cursor.rs
|
// src/canvas/cursor.rs
|
||||||
//! Cursor style management for different canvas modes
|
//! Cursor style management for different canvas modes
|
||||||
|
//!
|
||||||
|
//! Provides helpers to update and reset terminal cursor style when the
|
||||||
|
//! `cursor-style` feature is enabled. When the feature is disabled the
|
||||||
|
//! functions are no-ops.
|
||||||
|
|
||||||
#[cfg(feature = "cursor-style")]
|
#[cfg(feature = "cursor-style")]
|
||||||
use crossterm::{cursor::SetCursorStyle, execute};
|
use crossterm::{cursor::SetCursorStyle, execute};
|
||||||
@@ -12,7 +16,10 @@ use crate::canvas::modes::AppMode;
|
|||||||
pub struct CursorManager;
|
pub struct CursorManager;
|
||||||
|
|
||||||
impl CursorManager {
|
impl CursorManager {
|
||||||
/// Update cursor style based on current mode
|
/// Update cursor style based on current mode.
|
||||||
|
///
|
||||||
|
/// When the `textmode-normal` feature is enabled a fixed style is applied.
|
||||||
|
/// Otherwise, the cursor style is mapped to the provided AppMode.
|
||||||
#[cfg(feature = "cursor-style")]
|
#[cfg(feature = "cursor-style")]
|
||||||
pub fn update_for_mode(mode: AppMode) -> io::Result<()> {
|
pub fn update_for_mode(mode: AppMode) -> io::Result<()> {
|
||||||
// NORMALMODE: force underscore for every mode
|
// NORMALMODE: force underscore for every mode
|
||||||
@@ -37,18 +44,19 @@ impl CursorManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// No-op when cursor-style feature is disabled
|
/// No-op when cursor-style feature is disabled.
|
||||||
#[cfg(not(feature = "cursor-style"))]
|
#[cfg(not(feature = "cursor-style"))]
|
||||||
pub fn update_for_mode(_mode: AppMode) -> io::Result<()> {
|
pub fn update_for_mode(_mode: AppMode) -> io::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset cursor to default on cleanup
|
/// Reset cursor to default on cleanup.
|
||||||
#[cfg(feature = "cursor-style")]
|
#[cfg(feature = "cursor-style")]
|
||||||
pub fn reset() -> io::Result<()> {
|
pub fn reset() -> io::Result<()> {
|
||||||
execute!(io::stdout(), SetCursorStyle::DefaultUserShape)
|
execute!(io::stdout(), SetCursorStyle::DefaultUserShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reset is a no-op when the cursor-style feature is disabled.
|
||||||
#[cfg(not(feature = "cursor-style"))]
|
#[cfg(not(feature = "cursor-style"))]
|
||||||
pub fn reset() -> io::Result<()> {
|
pub fn reset() -> io::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
// src/canvas/gui.rs
|
// src/canvas/gui.rs
|
||||||
//! Canvas GUI updated to work with FormEditor
|
//! Canvas GUI updated to work with FormEditor
|
||||||
|
//!
|
||||||
|
//! This module provides rendering helpers for the canvas UI when the `gui`
|
||||||
|
//! feature is enabled. It exposes high-level functions to render the canvas
|
||||||
|
//! and convenience types for display options.
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
#[cfg(feature = "gui")]
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
@@ -22,14 +26,20 @@ use std::cmp::{max, min};
|
|||||||
|
|
||||||
#[cfg(feature = "gui")]
|
#[cfg(feature = "gui")]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
/// How to handle overflow when rendering a field's content.
|
||||||
pub enum OverflowMode {
|
pub enum OverflowMode {
|
||||||
Indicator(char), // default '$'
|
/// Show an indicator character at the left/right when text is truncated.
|
||||||
|
/// Common default is '$'.
|
||||||
|
Indicator(char),
|
||||||
|
/// Wrap content into multiple visual lines.
|
||||||
Wrap,
|
Wrap,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
#[cfg(feature = "gui")]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
/// Display options controlling canvas rendering behavior.
|
||||||
pub struct CanvasDisplayOptions {
|
pub struct CanvasDisplayOptions {
|
||||||
|
/// How to handle horizontal overflow for fields.
|
||||||
pub overflow: OverflowMode,
|
pub overflow: OverflowMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +201,9 @@ fn render_active_line_with_indicator<T: CanvasTheme>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
#[cfg(feature = "gui")]
|
||||||
|
/// Render the canvas into the provided frame using default display options.
|
||||||
|
///
|
||||||
|
/// Returns the rectangle of the active input field if present.
|
||||||
pub fn render_canvas<T: CanvasTheme, D: DataProvider>(
|
pub fn render_canvas<T: CanvasTheme, D: DataProvider>(
|
||||||
f: &mut Frame,
|
f: &mut Frame,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
@@ -202,6 +215,10 @@ pub fn render_canvas<T: CanvasTheme, D: DataProvider>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
#[cfg(feature = "gui")]
|
||||||
|
/// Render the canvas into the provided frame with explicit display options.
|
||||||
|
///
|
||||||
|
/// This is the more configurable entrypoint for rendering and is useful for
|
||||||
|
/// tests or when callers need to override overflow handling.
|
||||||
pub fn render_canvas_with_options<T: CanvasTheme, D: DataProvider>(
|
pub fn render_canvas_with_options<T: CanvasTheme, D: DataProvider>(
|
||||||
f: &mut Frame,
|
f: &mut Frame,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
// src/canvas/mod.rs
|
// src/canvas/mod.rs
|
||||||
|
//! Top-level canvas module.
|
||||||
|
//!
|
||||||
|
//! Re-exports commonly used canvas types and modules so that downstream
|
||||||
|
//! consumers can import them from `crate::canvas`.
|
||||||
|
|
||||||
pub mod actions;
|
pub mod actions;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
// src/state/app/highlight.rs
|
// src/canvas/modes/highlight.rs
|
||||||
// canvas/src/modes/highlight.rs
|
//! Highlight state definitions for canvas visual/selection modes.
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
/// Represents the current highlight/visual selection state.
|
||||||
|
///
|
||||||
|
/// This enum is used by the GUI and selection logic to track whether a visual
|
||||||
|
/// selection is active and its anchor position.
|
||||||
pub enum HighlightState {
|
pub enum HighlightState {
|
||||||
|
/// No highlighting active.
|
||||||
#[default]
|
#[default]
|
||||||
Off,
|
Off,
|
||||||
|
/// Characterwise selection with an anchor (field_index, char_position).
|
||||||
Characterwise { anchor: (usize, usize) }, // (field_index, char_position)
|
Characterwise { anchor: (usize, usize) }, // (field_index, char_position)
|
||||||
|
/// Linewise selection anchored at a field index.
|
||||||
Linewise { anchor_line: usize }, // field_index
|
Linewise { anchor_line: usize }, // field_index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +1,61 @@
|
|||||||
// src/modes/handlers/mode_manager.rs
|
// src/modes/handlers/mode_manager.rs
|
||||||
// canvas/src/modes/manager.rs
|
// canvas/src/modes/manager.rs
|
||||||
|
//! Mode manager utilities and the AppMode enum.
|
||||||
|
//!
|
||||||
|
//! This module defines the available canvas modes and provides helper
|
||||||
|
//! functions to validate mode transitions and perform required side-effects
|
||||||
|
//! such as updating cursor style when enabled.
|
||||||
|
|
||||||
#[cfg(feature = "cursor-style")]
|
#[cfg(feature = "cursor-style")]
|
||||||
use crate::canvas::CursorManager;
|
use crate::canvas::CursorManager;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
/// Top-level application modes used by the canvas UI.
|
||||||
|
///
|
||||||
|
/// These modes control input handling, cursor behavior, and how the UI should
|
||||||
|
/// respond to user actions.
|
||||||
pub enum AppMode {
|
pub enum AppMode {
|
||||||
General, // For intro and admin screens
|
/// For intro and admin screens
|
||||||
ReadOnly, // Canvas read-only mode
|
General,
|
||||||
Edit, // Canvas edit mode
|
/// Canvas read-only mode (navigation)
|
||||||
Highlight, // Canvas highlight/visual mode
|
ReadOnly,
|
||||||
Command, // Command mode overlay
|
/// Canvas edit mode (insertion/modification)
|
||||||
|
Edit,
|
||||||
|
/// Canvas highlight/visual mode (selection)
|
||||||
|
Highlight,
|
||||||
|
/// Command mode overlay (for commands)
|
||||||
|
Command,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ModeManager;
|
pub struct ModeManager;
|
||||||
|
|
||||||
impl ModeManager {
|
impl ModeManager {
|
||||||
// Mode transition rules
|
// Mode transition rules
|
||||||
|
|
||||||
|
/// Return true if the system can enter Command mode from the given current mode.
|
||||||
pub fn can_enter_command_mode(current_mode: AppMode) -> bool {
|
pub fn can_enter_command_mode(current_mode: AppMode) -> bool {
|
||||||
!matches!(current_mode, AppMode::Edit)
|
!matches!(current_mode, AppMode::Edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if the system can enter Edit mode from the given current mode.
|
||||||
pub fn can_enter_edit_mode(current_mode: AppMode) -> bool {
|
pub fn can_enter_edit_mode(current_mode: AppMode) -> bool {
|
||||||
matches!(current_mode, AppMode::ReadOnly)
|
matches!(current_mode, AppMode::ReadOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if the system can enter ReadOnly mode from the given current mode.
|
||||||
pub fn can_enter_read_only_mode(current_mode: AppMode) -> bool {
|
pub fn can_enter_read_only_mode(current_mode: AppMode) -> bool {
|
||||||
matches!(current_mode, AppMode::Edit | AppMode::Command | AppMode::Highlight)
|
matches!(current_mode, AppMode::Edit | AppMode::Command | AppMode::Highlight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if the system can enter Highlight mode from the given current mode.
|
||||||
pub fn can_enter_highlight_mode(current_mode: AppMode) -> bool {
|
pub fn can_enter_highlight_mode(current_mode: AppMode) -> bool {
|
||||||
matches!(current_mode, AppMode::ReadOnly)
|
matches!(current_mode, AppMode::ReadOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Transition to new mode with automatic cursor update (when cursor-style feature enabled)
|
/// Transition to new mode with automatic cursor update (when cursor-style feature enabled).
|
||||||
|
///
|
||||||
|
/// Returns the resulting mode or an I/O error if cursor style update fails.
|
||||||
pub fn transition_to_mode(current_mode: AppMode, new_mode: AppMode) -> std::io::Result<AppMode> {
|
pub fn transition_to_mode(current_mode: AppMode, new_mode: AppMode) -> std::io::Result<AppMode> {
|
||||||
#[cfg(feature = "textmode-normal")]
|
#[cfg(feature = "textmode-normal")]
|
||||||
{
|
{
|
||||||
@@ -54,7 +75,10 @@ impl ModeManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enter highlight mode with cursor styling
|
/// Enter highlight mode with cursor styling.
|
||||||
|
///
|
||||||
|
/// Returns Ok(true) if the transition succeeded (and cursor style was updated
|
||||||
|
/// when enabled), otherwise Ok(false) if the transition is not allowed.
|
||||||
pub fn enter_highlight_mode_with_cursor(current_mode: AppMode) -> std::io::Result<bool> {
|
pub fn enter_highlight_mode_with_cursor(current_mode: AppMode) -> std::io::Result<bool> {
|
||||||
if Self::can_enter_highlight_mode(current_mode) {
|
if Self::can_enter_highlight_mode(current_mode) {
|
||||||
#[cfg(feature = "cursor-style")]
|
#[cfg(feature = "cursor-style")]
|
||||||
@@ -67,7 +91,10 @@ impl ModeManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exit highlight mode with cursor styling
|
/// Exit highlight mode with cursor styling and return the next mode.
|
||||||
|
///
|
||||||
|
/// This helper returns the mode to switch to (ReadOnly) and updates cursor
|
||||||
|
/// style if the feature is enabled.
|
||||||
pub fn exit_highlight_mode_with_cursor() -> std::io::Result<AppMode> {
|
pub fn exit_highlight_mode_with_cursor() -> std::io::Result<AppMode> {
|
||||||
let new_mode = AppMode::ReadOnly;
|
let new_mode = AppMode::ReadOnly;
|
||||||
#[cfg(feature = "cursor-style")]
|
#[cfg(feature = "cursor-style")]
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
// src/canvas/state.rs
|
// src/canvas/state.rs
|
||||||
//! Library-owned UI state - user never directly modifies this
|
//! Library-owned UI state - user never directly modifies this
|
||||||
|
//!
|
||||||
|
//! This module exposes the EditorState type (and related selection and
|
||||||
|
//! suggestions types) which represent the internal UI state maintained by the
|
||||||
|
//! canvas library. These types are intended for read-only access by callers
|
||||||
|
//! and are mutated only through the library's APIs.
|
||||||
|
|
||||||
use crate::canvas::modes::AppMode;
|
use crate::canvas::modes::AppMode;
|
||||||
|
|
||||||
/// Library-owned UI state - user never directly modifies this
|
/// Library-owned UI state - user never directly modifies this
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
/// Internal editor UI state managed by the canvas library.
|
||||||
|
///
|
||||||
|
/// The fields are `pub(crate)` because they should only be modified by the
|
||||||
|
/// library's internal action handlers. Consumers can use the provided getter
|
||||||
|
/// methods to observe the state.
|
||||||
pub struct EditorState {
|
pub struct EditorState {
|
||||||
// Navigation state
|
// Navigation state
|
||||||
pub(crate) current_field: usize,
|
pub(crate) current_field: usize,
|
||||||
@@ -32,6 +42,7 @@ pub struct EditorState {
|
|||||||
|
|
||||||
#[cfg(feature = "suggestions")]
|
#[cfg(feature = "suggestions")]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
/// Internal suggestions UI state used to manage the suggestions dropdown.
|
||||||
pub struct SuggestionsUIState {
|
pub struct SuggestionsUIState {
|
||||||
pub(crate) is_active: bool,
|
pub(crate) is_active: bool,
|
||||||
pub(crate) is_loading: bool,
|
pub(crate) is_loading: bool,
|
||||||
@@ -42,13 +53,19 @@ pub struct SuggestionsUIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
/// SelectionState represents the current selection/visual mode state used by
|
||||||
|
/// the canvas (for example, Vim-like visual modes).
|
||||||
pub enum SelectionState {
|
pub enum SelectionState {
|
||||||
|
/// No selection is active.
|
||||||
None,
|
None,
|
||||||
|
/// Characterwise selection: (field_index, char_position)
|
||||||
Characterwise { anchor: (usize, usize) },
|
Characterwise { anchor: (usize, usize) },
|
||||||
|
/// Linewise selection anchored at a field (field index).
|
||||||
Linewise { anchor_field: usize },
|
Linewise { anchor_field: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditorState {
|
impl EditorState {
|
||||||
|
/// Create a new EditorState with default initial values.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
current_field: 0,
|
current_field: 0,
|
||||||
@@ -139,6 +156,10 @@ impl EditorState {
|
|||||||
// INTERNAL MUTATIONS: Only library modifies these
|
// INTERNAL MUTATIONS: Only library modifies these
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
|
/// Move internal pointer to another field index.
|
||||||
|
///
|
||||||
|
/// This method is intended for internal library use to change the current
|
||||||
|
/// field and reset the cursor to a safe value.
|
||||||
pub(crate) fn move_to_field(&mut self, field_index: usize, field_count: usize) {
|
pub(crate) fn move_to_field(&mut self, field_index: usize, field_count: usize) {
|
||||||
if field_index < field_count {
|
if field_index < field_count {
|
||||||
self.current_field = field_index;
|
self.current_field = field_index;
|
||||||
@@ -147,6 +168,11 @@ impl EditorState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the cursor position with appropriate clamping depending on mode.
|
||||||
|
///
|
||||||
|
/// If `for_edit_mode` is true the cursor may be positioned at the end of
|
||||||
|
/// the text (allowing insertion); otherwise it will be kept within the
|
||||||
|
/// bounds of the existing text for read-only/highlight modes.
|
||||||
pub(crate) fn set_cursor(
|
pub(crate) fn set_cursor(
|
||||||
&mut self,
|
&mut self,
|
||||||
position: usize,
|
position: usize,
|
||||||
|
|||||||
Reference in New Issue
Block a user