Application State Management
May 18, 2026 · View on GitHub
Overview
The state.rs module provides comprehensive application state management for Ferrite. It defines the central AppState struct that manages all runtime data including open tabs, user settings, and UI state.
Key Files
src/state.rs- Main state module with all state types and logic
Core Types
FileType - File Type Detection
Enum for adaptive UI based on file extension:
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FileType {
#[default]
Markdown, // .md, .markdown
Json, // .json
Yaml, // .yaml, .yml
Toml, // .toml
Unknown, // Other extensions
}
impl FileType {
pub fn from_path(path: &Path) -> Self;
pub fn from_extension(ext: &str) -> Self;
pub fn is_markdown(&self) -> bool;
pub fn is_structured(&self) -> bool; // JSON, YAML, or TOML
pub fn display_name(&self) -> &'static str;
}
Tab - Document State
Runtime state for an open document tab with full editing support.
pub struct Tab {
pub id: usize, // Unique tab identifier
pub path: Option<PathBuf>, // File path (None = unsaved)
pub content: String, // Current content
pub cursor_position: (usize, usize), // (line, column)
pub scroll_offset: f32, // Scroll position
pub view_mode: ViewMode, // Raw or Rendered mode (per-tab)
pub file_type: FileType, // Detected file type for adaptive UI
// Private: undo/redo stacks, original content
}
Key Methods:
new(id)/with_file(id, path, content)- Creationfrom_tab_info(id, info, content)- Restore from sessionis_modified()- Check for unsaved changestitle()- Display name (with*for modified)set_content(text)- Update content (pushes to undo stack)undo()/redo()- History navigationmark_saved()- Reset modification trackingto_tab_info()- Convert toTabInfofor persistencetoggle_view_mode()- Switch between Raw/Renderedget_view_mode()/set_view_mode()- View mode access
UiState - UI Flags
Tracks visibility and state of UI elements.
pub struct UiState {
pub show_settings: bool,
pub show_file_dialog: bool,
pub show_save_as_dialog: bool,
pub show_about: bool,
pub show_confirm_dialog: bool,
pub confirm_dialog_message: String,
pub pending_action: Option<PendingAction>,
pub status_message: Option<String>, // Deprecated, use toast
pub show_find_replace: bool,
pub search_query: String,
pub replace_text: String,
pub show_error_modal: bool,
pub error_message: String,
pub toast_message: Option<String>, // Temporary notification
pub toast_expires_at: Option<f64>, // When toast should disappear
pub show_recent_files_popup: bool, // Recent files menu
// Workspace UI state
pub show_quick_switcher: bool, // Quick file palette (Ctrl+P)
pub show_search_panel: bool, // Search in files (Ctrl+Shift+F)
}
PendingAction - Confirmation Actions
Actions that may require user confirmation before execution.
pub enum PendingAction {
CloseTab(usize),
CloseAllTabs,
Exit,
OpenFile(PathBuf),
NewDocument,
}
AppState - Central State
The main application state container.
pub struct AppState {
tabs: Vec<Tab>,
active_tab_index: usize,
pub settings: Settings,
pub ui: UiState,
pub mode: AppMode, // Single file or workspace mode
pub workspace: Option<Workspace>, // Active workspace (if any)
// Private: next_tab_id, settings_dirty, workspace_watcher
}
AppMode - Application Mode
The application operates in one of two modes:
pub enum AppMode {
SingleFile, // Traditional single-file editing
Workspace { // Folder-based project mode
root: PathBuf,
settings_path: PathBuf, // .ferrite/ directory
},
}
Workspace - Workspace State
When a folder is opened, workspace state is managed:
pub struct Workspace {
pub root_path: PathBuf,
pub file_tree: FileTreeNode,
pub hidden_patterns: Vec<String>,
pub recent_files: Vec<PathBuf>,
pub settings: WorkspaceSettings,
pub show_file_tree: bool,
pub file_tree_width: f32,
}
See Workspace Folder Support for detailed workspace documentation.
Implementation Details
Initialization
AppState::new() performs:
- Loads settings via
load_config()(graceful fallback to defaults) - Creates initial empty tab
- Initializes default UI state
let state = AppState::new();
// Or with custom settings for testing:
let state = AppState::with_settings(Settings::default());
Tab Management
// Create tabs
let index = state.new_tab();
let index = state.open_file(path)?;
// Access tabs
let tab = state.active_tab();
let tab = state.active_tab_mut();
state.set_active_tab(1);
// Close tabs (respects unsaved changes)
state.close_tab(index); // Shows confirmation if modified
state.force_close_tab(index); // Ignores modifications
Undo/Redo System
Each tab maintains an independent EditHistory (500 undo groups by default, 200 for files ≥ 1 MB):
if let Some(tab) = state.active_tab_mut() {
tab.set_content("new text".to_string()); // Records diff as one undo group
tab.undo(); // Restores previous
tab.redo(); // Re-applies change
}
See Undo/Redo System.
Event Handling
Confirmation dialog workflow:
// Request exit (checks for unsaved changes)
if !state.request_exit() {
// Confirmation dialog shown via state.ui.show_confirm_dialog
}
// After user confirms
state.handle_confirmed_action();
// Or cancels
state.cancel_pending_action();
Settings Integration
// Update settings reactively
state.update_settings(|s| {
s.theme = Theme::Dark;
s.font_size = 16.0;
});
// Save to disk when dirty
state.save_settings_if_dirty();
// Shutdown (auto-saves)
state.shutdown();
Dependencies Used
crate::config::Settings- User preferencescrate::config::TabInfo- Tab persistence datacrate::config::load_config- Config loadingcrate::config::save_config_silent- Silent config savingcrate::error::Error- Error types for file operationslog- Logging (debug, info, warn)
Usage
use crate::state::AppState;
fn main() {
let mut state = AppState::new();
// Open a file
if let Ok(index) = state.open_file(PathBuf::from("doc.md")) {
println!("Opened in tab {}", index);
}
// Edit content
if let Some(tab) = state.active_tab_mut() {
tab.set_content("# Hello World".to_string());
}
// Save
state.save_active_tab().expect("Save failed");
// Cleanup
state.shutdown();
}
Tests
Run state module tests:
cargo test state::tests
Test Coverage:
- Tab creation and modification tracking
- Title generation with modification indicator
- Undo/redo functionality
- AppState initialization
- Tab management (create, switch, close)
- Unsaved changes detection
- Settings updates
- UI state toggles
- Event handling (confirm/cancel)
- Pending action system
Total: 24 tests in state::tests module