prod comments in the codebase

This commit is contained in:
Priec
2025-08-18 21:00:14 +02:00
parent 885a48bdd8
commit 465db82bd9
12 changed files with 163 additions and 29 deletions

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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 |

View File

@@ -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(())

View File

@@ -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,

View File

@@ -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;

View File

@@ -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
} }

View File

@@ -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")]

View File

@@ -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,