Skip to main content

tui_canvas/editor/
display.rs

1// src/editor/display.rs
2
3use crate::DataProvider;
4use crate::canvas::modes::AppMode;
5use crate::editor::EditorCore;
6
7impl<D: DataProvider> EditorCore<D> {
8    /// Get current field text for display.
9    #[cfg(feature = "validation")]
10    pub fn current_display_text(&self) -> String {
11        let field_index = self.ui_state.current_field;
12        let raw = if field_index < self.data_provider.field_count() {
13            self.data_provider.field_value(field_index)
14        } else {
15            ""
16        };
17
18        if let Some(cfg) = self.ui_state.validation.get_field_config(field_index) {
19            if cfg.custom_formatter.is_none() {
20                if let Some(mask) = &cfg.display_mask {
21                    return mask.apply_to_display(raw);
22                }
23            }
24
25            if cfg.custom_formatter.is_some() {
26                if matches!(self.ui_state.current_mode, AppMode::Ins) {
27                    return raw.to_string();
28                }
29                if let Some((formatted, _mapper, _warning)) = cfg.run_custom_formatter(raw) {
30                    return formatted;
31                }
32            }
33
34            if let Some(mask) = &cfg.display_mask {
35                return mask.apply_to_display(raw);
36            }
37        }
38
39        raw.to_string()
40    }
41
42    /// Get effective display text for any field index (Feature 4 + masks).
43    #[cfg(feature = "validation")]
44    pub fn display_text_for_field(&self, field_index: usize) -> String {
45        let raw = if field_index < self.data_provider.field_count() {
46            self.data_provider.field_value(field_index)
47        } else {
48            ""
49        };
50
51        if let Some(cfg) = self.ui_state.validation.get_field_config(field_index) {
52            if cfg.custom_formatter.is_none() {
53                if let Some(mask) = &cfg.display_mask {
54                    return mask.apply_to_display(raw);
55                }
56            }
57
58            if cfg.custom_formatter.is_some() {
59                if field_index == self.ui_state.current_field
60                    && matches!(self.ui_state.current_mode, AppMode::Ins)
61                {
62                    return raw.to_string();
63                }
64                if let Some((formatted, _mapper, _warning)) = cfg.run_custom_formatter(raw) {
65                    return formatted;
66                }
67            }
68
69            if let Some(mask) = &cfg.display_mask {
70                return mask.apply_to_display(raw);
71            }
72        }
73
74        raw.to_string()
75    }
76
77    /// Map raw cursor to display position (formatter/mask aware).
78    pub fn display_cursor_position(&self) -> usize {
79        let current_text = self.current_text();
80        let char_count = current_text.chars().count();
81
82        let raw_pos = match self.ui_state.current_mode {
83            AppMode::Ins => self.ui_state.cursor_pos.min(char_count),
84            _ => {
85                if char_count == 0 {
86                    0
87                } else {
88                    self.ui_state.cursor_pos.min(char_count.saturating_sub(1))
89                }
90            }
91        };
92
93        #[cfg(feature = "validation")]
94        {
95            let field_index = self.ui_state.current_field;
96            if let Some(cfg) = self.ui_state.validation.get_field_config(field_index) {
97                if !matches!(self.ui_state.current_mode, AppMode::Ins) {
98                    if let Some((formatted, mapper, _)) = cfg.run_custom_formatter(current_text) {
99                        return mapper.raw_to_formatted(current_text, &formatted, raw_pos);
100                    }
101                }
102                if let Some(mask) = &cfg.display_mask {
103                    return mask.raw_pos_to_display_pos(raw_pos);
104                }
105            }
106        }
107
108        raw_pos
109    }
110}