use crate::canvas::modes::AppMode;
#[derive(Debug, Clone)]
pub struct EditorState {
pub(crate) current_field: usize,
pub(crate) cursor_pos: usize,
pub(crate) ideal_cursor_column: usize,
pub(crate) current_mode: AppMode,
#[cfg(feature = "suggestions")]
pub(crate) suggestions: SuggestionsUIState,
pub(crate) selection: SelectionState,
#[cfg(feature = "validation")]
pub(crate) validation: crate::validation::ValidationState,
#[cfg(feature = "computed")]
pub(crate) computed: Option<crate::computed::ComputedState>,
}
#[cfg(feature = "suggestions")]
#[derive(Debug, Clone)]
pub struct SuggestionsUIState {
pub(crate) is_active: bool,
pub(crate) is_loading: bool,
pub(crate) selected_index: Option<usize>,
pub(crate) active_field: Option<usize>,
pub(crate) active_query: Option<String>,
pub(crate) replace_range: Option<(usize, usize)>,
pub(crate) completion_text: Option<String>,
}
#[derive(Debug, Clone)]
pub enum SelectionState {
None,
Characterwise { anchor: (usize, usize) },
Linewise { anchor_field: usize },
}
impl EditorState {
pub fn new() -> Self {
Self {
current_field: 0,
cursor_pos: 0,
ideal_cursor_column: 0,
#[cfg(feature = "textmode-normal")]
current_mode: AppMode::Ins,
#[cfg(not(feature = "textmode-normal"))]
current_mode: AppMode::Nor,
#[cfg(feature = "suggestions")]
suggestions: SuggestionsUIState {
is_active: false,
is_loading: false,
selected_index: None,
active_field: None,
active_query: None,
replace_range: None,
completion_text: None,
},
selection: SelectionState::None,
#[cfg(feature = "validation")]
validation: crate::validation::ValidationState::new(),
#[cfg(feature = "computed")]
computed: None,
}
}
pub fn current_field(&self) -> usize {
self.current_field
}
#[cfg(feature = "computed")]
pub fn is_computed_field(&self, field_index: usize) -> bool {
self.computed
.as_ref()
.map(|state| state.is_computed_field(field_index))
.unwrap_or(false)
}
pub fn cursor_position(&self) -> usize {
self.cursor_pos
}
pub fn ideal_cursor_column(&self) -> usize {
self.ideal_cursor_column
}
pub fn mode(&self) -> AppMode {
self.current_mode
}
#[cfg(feature = "suggestions")]
pub fn is_suggestions_active(&self) -> bool {
self.suggestions.is_active
}
#[cfg(feature = "suggestions")]
pub fn is_suggestions_loading(&self) -> bool {
self.suggestions.is_loading
}
pub fn selection_state(&self) -> &SelectionState {
&self.selection
}
#[cfg(feature = "validation")]
pub fn validation_state(&self) -> &crate::validation::ValidationState {
&self.validation
}
pub(crate) fn move_to_field(&mut self, field_index: usize, field_count: usize) {
if field_index < field_count {
self.current_field = field_index;
self.set_cursor(0, 0, true);
}
}
pub(crate) fn set_cursor(&mut self, position: usize, max_position: usize, for_edit_mode: bool) {
if for_edit_mode {
self.cursor_pos = position.min(max_position);
} else {
self.cursor_pos = position.min(max_position.saturating_sub(1));
}
self.ideal_cursor_column = self.cursor_pos;
}
#[cfg(feature = "suggestions")]
pub(crate) fn open_suggestions(&mut self, field_index: usize) {
self.suggestions.is_active = true;
self.suggestions.is_loading = true;
self.suggestions.active_field = Some(field_index);
self.suggestions.active_query = None;
self.suggestions.replace_range = None;
self.suggestions.selected_index = None;
self.suggestions.completion_text = None;
}
#[cfg(feature = "suggestions")]
pub(crate) fn close_suggestions(&mut self) {
self.suggestions.is_active = false;
self.suggestions.is_loading = false;
self.suggestions.active_field = None;
self.suggestions.active_query = None;
self.suggestions.replace_range = None;
self.suggestions.selected_index = None;
self.suggestions.completion_text = None;
}
}
impl Default for EditorState {
fn default() -> Self {
Self::new()
}
}