hjkl_engine/discipline.rs
1//! Pluggable input-discipline state (#265 G3 / #267).
2//!
3//! The engine owns the editing *core* (buffer, undo, registers, marks,
4//! search, viewport) but is agnostic about the *keybinding discipline* (vim,
5//! vscode, future helix/emacs). Each discipline's FSM state lives in its own
6//! crate (e.g. `hjkl-vim`'s `VimState`) and is stored on the [`Editor`] through
7//! this type-erased slot — the engine never names the concrete state type.
8//!
9//! The trait is intentionally **minimal**: the engine only asks a discipline
10//! for its [`CoarseMode`] (status badge / cursor shape) plus an `Any` upcast.
11//! All discipline-specific behavior lives behind that downcast in the
12//! discipline crate (e.g. `hjkl_vim::vim_state`), never on this trait.
13//!
14//! [`Editor`]: crate::Editor
15
16use crate::CoarseMode;
17
18/// Discipline-private FSM state, stored type-erased on the [`Editor`].
19///
20/// [`Editor`]: crate::Editor
21pub trait DisciplineState: std::any::Any + std::fmt::Debug {
22 /// Discipline-agnostic coarse mode for app chrome (status badge, cursor
23 /// shape). Every discipline projects its internal mode onto this.
24 fn coarse_mode(&self) -> CoarseMode;
25
26 /// Upcast to `&dyn Any` so the owning crate can `downcast_ref` to its
27 /// concrete state type.
28 fn as_any(&self) -> &dyn std::any::Any;
29
30 /// Mutable upcast — see [`DisciplineState::as_any`].
31 fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
32}
33
34/// Default discipline for an [`Editor`] that has not had a real discipline
35/// installed: no FSM, always reports [`CoarseMode::Normal`]. Editors that
36/// receive vim/vscode/etc. input install their discipline at construction
37/// (e.g. `hjkl_vim::install_vim_discipline`).
38///
39/// [`Editor`]: crate::Editor
40#[derive(Debug, Default)]
41pub struct NoDiscipline;
42
43impl DisciplineState for NoDiscipline {
44 fn coarse_mode(&self) -> CoarseMode {
45 CoarseMode::Normal
46 }
47 fn as_any(&self) -> &dyn std::any::Any {
48 self
49 }
50 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
51 self
52 }
53}