urushi_prompt/runtime/
field.rs1use std::any::Any;
4
5use super::{
6 terminal::Event,
7 view::{FieldPresentation, PromptStyles},
8};
9
10#[allow(
15 private_bounds,
16 reason = "Field stays externally sealed while crate sibling field modules implement its runtime seam."
17)]
18pub trait Field: private::Sealed + 'static {}
19
20impl<T> Field for T where T: private::Sealed + 'static {}
21
22pub(crate) mod private {
23 pub(crate) trait Sealed {
24 fn into_entry(self: Box<Self>) -> super::FieldEntry;
25 }
26}
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub(super) enum FieldState {
29 Active,
30 Invalid { message: String },
31 Accepted,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub(crate) enum FieldAction {
36 Stay,
37 Handled,
38 Accept,
39 Back,
40 Cancel,
41}
42
43pub(crate) struct FieldEntry {
44 pub(super) name: String,
45 pub(super) state: FieldState,
46 pub(super) field: Box<dyn RuntimeField>,
47}
48
49impl FieldEntry {
50 pub(crate) fn new(name: String, field: Box<dyn RuntimeField>) -> Self {
51 Self {
52 name,
53 state: FieldState::Active,
54 field,
55 }
56 }
57
58 pub(super) fn name(&self) -> &str {
59 &self.name
60 }
61
62 pub(super) fn event(&mut self, event: Event) -> FieldAction {
63 let action = self.field.event(event);
64 self.state = match self.field.validation_error() {
65 Some(message) => FieldState::Invalid {
66 message: message.to_owned(),
67 },
68 None => FieldState::Active,
69 };
70 action
71 }
72
73 pub(super) fn activate(&mut self) {
74 self.field.focus();
75 self.state = FieldState::Active;
76 }
77
78 pub(super) fn deactivate(&mut self) {
79 self.field.blur();
80 }
81
82 pub(super) fn accept(&mut self) {
83 self.field.blur();
84 self.state = FieldState::Accepted;
85 }
86
87 pub(super) fn take_value(&mut self) -> Box<dyn Any> {
88 self.field.take_value()
89 }
90
91 pub(super) fn view(
92 &self,
93 styles: &PromptStyles,
94 focused: bool,
95 width: usize,
96 ) -> FieldPresentation {
97 self.field.view(styles, focused, width)
98 }
99
100 pub(super) fn captures_tab(&self) -> bool {
101 self.field.captures_tab()
102 }
103}
104
105pub(crate) trait RuntimeField {
106 fn event(&mut self, event: Event) -> FieldAction;
107 fn take_value(&mut self) -> Box<dyn Any>;
108 fn view(&self, styles: &PromptStyles, focused: bool, width: usize) -> FieldPresentation;
120
121 fn validation_error(&self) -> Option<&str> {
122 None
123 }
124
125 fn focus(&mut self) {}
126
127 fn blur(&mut self) {}
128
129 fn captures_tab(&self) -> bool {
130 false
131 }
132}