aboutsummaryrefslogtreecommitdiff
path: root/src/components.rs
diff options
context:
space:
mode:
authorrottedfm <rottedfm@proton.me>2026-08-19 11:21:47 -0400
committerrottedfm <rottedfm@proton.me>2026-08-19 11:21:47 -0400
commitea0bd36167b684c0accdb5ce2b2e21b8d84aeb25 (patch)
treebe1267972b5de2f1ae592577dfabce67f1fe6e87 /src/components.rs
parent8c0b4c53b130555f040884c1f52b90f16b23e241 (diff)
feat: implement Helix-style modal buffer under DO-178C DAL-C
The repository was an unmodified ratatui component template: no editor code, JSON5 config, and placeholder widgets. This establishes the first working baseline — `moji <file>` opens a file into a ropey rope and edits it with Helix selection-first semantics. Requirements, implementation and tests land together because they must: the traceability check rejects requirements with no implementation and tests naming requirements that do not exist, so neither half is a valid commit on its own. Package renamed to mojibake-editor (mojibake was taken on crates.io); binary is moji, library target stays mojibake. Class: New behaviour Requirements: MJB-HLR-001..019, MJB-LLR-001..205 Derived: MJB-DR-001..007 (DR-001 resolved, six open for review) Verified: cargo build; clippy --all-targets -D warnings clean; cargo test 294 passing; ./scripts/check-trace.sh 98/98/98; cargo package clean Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'src/components.rs')
-rw-r--r--src/components.rs125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/components.rs b/src/components.rs
new file mode 100644
index 0000000..1771a17
--- /dev/null
+++ b/src/components.rs
@@ -0,0 +1,125 @@
+use crossterm::event::{KeyEvent, MouseEvent};
+use ratatui::{
+ Frame,
+ layout::{Rect, Size},
+};
+use tokio::sync::mpsc::UnboundedSender;
+
+use crate::{action::Action, config::Config, tui::Event};
+
+// MJB-LLR-204, MJB-HLR-019: the buffer is the only widget. The template's
+// `fps` and `home` modules were deleted, not merely unregistered.
+pub mod buffer;
+
+/// `Component` is a trait that represents a visual and interactive element of the user interface.
+///
+/// Implementors of this trait can be registered with the main application loop and will be able to
+/// receive events, update state, and be rendered on the screen.
+pub trait Component {
+ /// Register an action handler that can send actions for processing if necessary.
+ ///
+ /// # Arguments
+ ///
+ /// * `tx` - An unbounded sender that can send actions.
+ ///
+ /// # Returns
+ ///
+ /// * [`color_eyre::Result<()>`] - An Ok result or an error.
+ fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> color_eyre::Result<()> {
+ let _ = tx; // to appease clippy
+ Ok(())
+ }
+ /// Register a configuration handler that provides configuration settings if necessary.
+ ///
+ /// # Arguments
+ ///
+ /// * `config` - Configuration settings.
+ ///
+ /// # Returns
+ ///
+ /// * [`color_eyre::Result<()>`] - An Ok result or an error.
+ fn register_config_handler(&mut self, config: Config) -> color_eyre::Result<()> {
+ let _ = config; // to appease clippy
+ Ok(())
+ }
+ /// Initialize the component with a specified area if necessary.
+ ///
+ /// # Arguments
+ ///
+ /// * `area` - Rectangular area to initialize the component within.
+ ///
+ /// # Returns
+ ///
+ /// * [`color_eyre::Result<()>`] - An Ok result or an error.
+ fn init(&mut self, area: Size) -> color_eyre::Result<()> {
+ let _ = area; // to appease clippy
+ Ok(())
+ }
+ /// Handle incoming events and produce actions if necessary.
+ ///
+ /// # Arguments
+ ///
+ /// * `event` - An optional event to be processed.
+ ///
+ /// # Returns
+ ///
+ /// * [`color_eyre::Result<Option<Action>>`] - An action to be processed or none.
+ fn handle_events(&mut self, event: Option<Event>) -> color_eyre::Result<Option<Action>> {
+ let action = match event {
+ Some(Event::Key(key_event)) => self.handle_key_event(key_event)?,
+ Some(Event::Mouse(mouse_event)) => self.handle_mouse_event(mouse_event)?,
+ _ => None,
+ };
+ Ok(action)
+ }
+ /// Handle key events and produce actions if necessary.
+ ///
+ /// # Arguments
+ ///
+ /// * `key` - A key event to be processed.
+ ///
+ /// # Returns
+ ///
+ /// * [`color_eyre::Result<Option<Action>>`] - An action to be processed or none.
+ fn handle_key_event(&mut self, key: KeyEvent) -> color_eyre::Result<Option<Action>> {
+ let _ = key; // to appease clippy
+ Ok(None)
+ }
+ /// Handle mouse events and produce actions if necessary.
+ ///
+ /// # Arguments
+ ///
+ /// * `mouse` - A mouse event to be processed.
+ ///
+ /// # Returns
+ ///
+ /// * [`color_eyre::Result<Option<Action>>`] - An action to be processed or none.
+ fn handle_mouse_event(&mut self, mouse: MouseEvent) -> color_eyre::Result<Option<Action>> {
+ let _ = mouse; // to appease clippy
+ Ok(None)
+ }
+ /// Update the state of the component based on a received action. (REQUIRED)
+ ///
+ /// # Arguments
+ ///
+ /// * `action` - An action that may modify the state of the component.
+ ///
+ /// # Returns
+ ///
+ /// * [`color_eyre::Result<Option<Action>>`] - An action to be processed or none.
+ fn update(&mut self, action: Action) -> color_eyre::Result<Option<Action>> {
+ let _ = action; // to appease clippy
+ Ok(None)
+ }
+ /// Render the component on the screen. (REQUIRED)
+ ///
+ /// # Arguments
+ ///
+ /// * `f` - A frame used for rendering.
+ /// * `area` - The area in which the component should be drawn.
+ ///
+ /// # Returns
+ ///
+ /// * [`color_eyre::Result<()>`] - An Ok result or an error.
+ fn draw(&mut self, frame: &mut Frame, area: Rect) -> color_eyre::Result<()>;
+}