1use std::cell::RefCell;
2use std::rc::Rc;
3use std::sync::Arc;
4
5use crate::app_state_container::AppStateContainer;
6use crate::buffer::{AppMode, Buffer, BufferAPI, BufferManager};
7use crate::config::config::Config;
8use crate::data::data_view::DataView;
9use crate::sql::hybrid_parser::HybridParser;
10use crate::ui::viewport_manager::ViewportManager;
11use crate::widgets::search_modes_widget::SearchMode;
12
13use tracing::{debug, error};
14
15pub struct StateCoordinator {
18 pub state_container: AppStateContainer,
20
21 pub shadow_state: Rc<RefCell<crate::ui::state::shadow_state::ShadowStateManager>>,
23
24 pub viewport_manager: Rc<RefCell<Option<ViewportManager>>>,
26
27 pub hybrid_parser: HybridParser,
29}
30
31impl StateCoordinator {
32 pub fn sync_mode_with_refs(
38 state_container: &mut AppStateContainer,
39 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
40 mode: AppMode,
41 trigger: &str,
42 ) {
43 debug!(
44 "StateCoordinator::sync_mode_with_refs: Setting mode to {:?} with trigger '{}'",
45 mode, trigger
46 );
47
48 state_container.set_mode(mode.clone());
50
51 if let Some(buffer) = state_container.buffers_mut().current_mut() {
53 buffer.set_mode(mode.clone());
54 }
55
56 shadow_state.borrow_mut().observe_mode_change(mode, trigger);
58 }
59
60 pub fn update_parser_with_refs(state_container: &AppStateContainer, parser: &mut HybridParser) {
62 if let Some(dataview) = state_container.get_buffer_dataview() {
63 let table_name = dataview.source().name.clone();
64 let columns = dataview.source().column_names();
65
66 debug!(
67 "StateCoordinator: Updating parser with {} columns for table '{}'",
68 columns.len(),
69 table_name
70 );
71 parser.update_single_table(table_name, columns);
72 }
73 }
74
75 pub fn new(
78 state_container: AppStateContainer,
79 shadow_state: Rc<RefCell<crate::ui::state::shadow_state::ShadowStateManager>>,
80 viewport_manager: Rc<RefCell<Option<ViewportManager>>>,
81 hybrid_parser: HybridParser,
82 ) -> Self {
83 Self {
84 state_container,
85 shadow_state,
86 viewport_manager,
87 hybrid_parser,
88 }
89 }
90
91 pub fn sync_mode(&mut self, mode: AppMode, trigger: &str) {
96 debug!(
97 "StateCoordinator::sync_mode: Setting mode to {:?} with trigger '{}'",
98 mode, trigger
99 );
100
101 self.state_container.set_mode(mode.clone());
103
104 if let Some(buffer) = self.state_container.buffers_mut().current_mut() {
106 buffer.set_mode(mode.clone());
107 }
108
109 self.shadow_state
111 .borrow_mut()
112 .observe_mode_change(mode, trigger);
113 }
114
115 pub fn set_mode_via_shadow_state(&mut self, mode: AppMode, trigger: &str) {
117 if let Some(buffer) = self.state_container.buffers_mut().current_mut() {
118 debug!(
119 "StateCoordinator::set_mode_via_shadow_state: Setting mode to {:?} with trigger '{}'",
120 mode, trigger
121 );
122 self.shadow_state
123 .borrow_mut()
124 .set_mode(mode, buffer, trigger);
125 } else {
126 error!(
127 "StateCoordinator::set_mode_via_shadow_state: No buffer available! Cannot set mode to {:?}",
128 mode
129 );
130 }
131 }
132
133 pub fn sync_after_buffer_switch(&mut self) {
138 self.update_parser_for_current_buffer();
141 }
142
143 pub fn update_parser_for_current_buffer(&mut self) {
145 if let Some(dataview) = self.state_container.get_buffer_dataview() {
147 let table_name = dataview.source().name.clone();
148 let columns = dataview.source().column_names();
149
150 debug!(
151 "StateCoordinator: Updating parser with {} columns for table '{}'",
152 columns.len(),
153 table_name
154 );
155 self.hybrid_parser.update_single_table(table_name, columns);
156 }
157 }
158
159 pub fn enter_search_mode(&mut self, mode: SearchMode) -> String {
163 debug!("StateCoordinator::enter_search_mode: {:?}", mode);
164
165 let trigger = match mode {
167 SearchMode::ColumnSearch => "backslash_column_search",
168 SearchMode::Search => "data_search_started",
169 SearchMode::FuzzyFilter => "fuzzy_filter_started",
170 SearchMode::Filter => "filter_started",
171 };
172
173 self.sync_mode(mode.to_app_mode(), trigger);
175
176 let search_type = match mode {
178 SearchMode::ColumnSearch => crate::ui::state::shadow_state::SearchType::Column,
179 SearchMode::Search => crate::ui::state::shadow_state::SearchType::Data,
180 SearchMode::FuzzyFilter | SearchMode::Filter => {
181 crate::ui::state::shadow_state::SearchType::Fuzzy
182 }
183 };
184 self.shadow_state
185 .borrow_mut()
186 .observe_search_start(search_type, trigger);
187
188 trigger.to_string()
189 }
190
191 pub fn cancel_search(&mut self) -> (Option<String>, Option<usize>) {
196 debug!("StateCoordinator::cancel_search: Canceling search and restoring state");
197
198 self.state_container.clear_search();
200
201 self.shadow_state
203 .borrow_mut()
204 .observe_search_end("search_cancelled");
205
206 self.sync_mode(AppMode::Results, "search_cancelled");
208
209 (None, None)
212 }
213
214 pub fn cancel_search_with_refs(
216 state_container: &mut AppStateContainer,
217 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
218 vim_search_adapter: Option<
219 &RefCell<crate::ui::search::vim_search_adapter::VimSearchAdapter>,
220 >,
221 ) {
222 debug!("StateCoordinator::cancel_search_with_refs: Canceling search and clearing all search state");
223
224 if let Some(adapter) = vim_search_adapter {
226 debug!("Clearing vim search adapter state");
227 adapter.borrow_mut().clear();
228 }
229
230 state_container.set_search_pattern(String::new());
232 state_container.clear_search();
233
234 state_container.clear_column_search();
236
237 shadow_state
239 .borrow_mut()
240 .observe_search_end("search_cancelled");
241
242 Self::sync_mode_with_refs(
244 state_container,
245 shadow_state,
246 AppMode::Results,
247 "vim_search_cancelled",
248 );
249 }
250
251 pub fn should_handle_next_match(
254 state_container: &AppStateContainer,
255 vim_search_adapter: Option<
256 &RefCell<crate::ui::search::vim_search_adapter::VimSearchAdapter>,
257 >,
258 ) -> bool {
259 let has_search = !state_container.get_search_pattern().is_empty();
261 let pattern = state_container.get_search_pattern();
262
263 let vim_active = if let Some(adapter) = vim_search_adapter {
266 let adapter_ref = adapter.borrow();
267 adapter_ref.is_active() || adapter_ref.is_navigating()
268 } else {
269 false
270 };
271
272 debug!(
273 "StateCoordinator::should_handle_next_match: pattern='{}', vim_active={}, result={}",
274 pattern,
275 vim_active,
276 has_search && vim_active
277 );
278
279 has_search && vim_active
281 }
282
283 pub fn should_handle_previous_match(
286 state_container: &AppStateContainer,
287 vim_search_adapter: Option<
288 &RefCell<crate::ui::search::vim_search_adapter::VimSearchAdapter>,
289 >,
290 ) -> bool {
291 let has_search = !state_container.get_search_pattern().is_empty();
293 let pattern = state_container.get_search_pattern();
294
295 let vim_active = if let Some(adapter) = vim_search_adapter {
298 let adapter_ref = adapter.borrow();
299 adapter_ref.is_active() || adapter_ref.is_navigating()
300 } else {
301 false
302 };
303
304 debug!(
305 "StateCoordinator::should_handle_previous_match: pattern='{}', vim_active={}, result={}",
306 pattern, vim_active, has_search && vim_active
307 );
308
309 has_search && vim_active
311 }
312
313 pub fn complete_search_with_refs(
316 state_container: &mut AppStateContainer,
317 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
318 vim_search_adapter: Option<
319 &RefCell<crate::ui::search::vim_search_adapter::VimSearchAdapter>,
320 >,
321 mode: AppMode,
322 trigger: &str,
323 ) {
324 debug!(
325 "StateCoordinator::complete_search_with_refs: Completing search, switching to {:?}",
326 mode
327 );
328
329 if let Some(adapter) = vim_search_adapter {
335 debug!("Marking vim search as complete but keeping matches");
336 adapter.borrow_mut().mark_search_complete();
337 }
338
339 shadow_state
341 .borrow_mut()
342 .observe_search_end("search_completed");
343
344 Self::sync_mode_with_refs(state_container, shadow_state, mode, trigger);
346 }
347
348 pub fn apply_text_filter_with_refs(
353 state_container: &mut AppStateContainer,
354 pattern: &str,
355 ) -> usize {
356 let case_insensitive = state_container.is_case_insensitive();
357
358 debug!(
359 "StateCoordinator::apply_text_filter_with_refs: Applying text filter with pattern '{}', case_sensitive: {}",
360 pattern, !case_insensitive
361 );
362
363 let rows_after = if let Some(dataview) = state_container.get_buffer_dataview_mut() {
365 let rows_before = dataview.row_count();
366 dataview.apply_text_filter(pattern, !case_insensitive);
367 let rows_after = dataview.row_count();
368 debug!(
369 "Text filter: {} rows before, {} rows after",
370 rows_before, rows_after
371 );
372 rows_after
373 } else {
374 debug!("No DataView available for text filtering");
375 0
376 };
377
378 let status = if pattern.is_empty() {
380 "Filter cleared".to_string()
381 } else {
382 format!("Filter applied: '{}' - {} matches", pattern, rows_after)
383 };
384 state_container.set_status_message(status);
385
386 debug!(
387 "StateCoordinator: Text filter applied - {} matches for pattern '{}'",
388 rows_after, pattern
389 );
390
391 rows_after
392 }
393
394 pub fn apply_fuzzy_filter_with_refs(
397 state_container: &mut AppStateContainer,
398 viewport_manager: &RefCell<Option<ViewportManager>>,
399 ) -> (usize, Vec<usize>) {
400 let pattern = state_container.get_fuzzy_filter_pattern();
401 let case_insensitive = state_container.is_case_insensitive();
402
403 debug!(
404 "StateCoordinator::apply_fuzzy_filter_with_refs: Applying fuzzy filter with pattern '{}', case_insensitive: {}",
405 pattern, case_insensitive
406 );
407
408 let (match_count, indices) =
410 if let Some(dataview) = state_container.get_buffer_dataview_mut() {
411 dataview.apply_fuzzy_filter(&pattern, case_insensitive);
412 let match_count = dataview.row_count();
413 let indices = dataview.get_fuzzy_filter_indices();
414 (match_count, indices)
415 } else {
416 (0, Vec::new())
417 };
418
419 if pattern.is_empty() {
421 state_container.set_fuzzy_filter_active(false);
422 state_container.set_status_message("Fuzzy filter cleared".to_string());
423 } else {
424 state_container.set_fuzzy_filter_active(true);
425 state_container.set_status_message(format!("Fuzzy filter: {} matches", match_count));
426
427 if match_count > 0 {
429 let col_offset = state_container.get_scroll_offset().1;
431
432 state_container.set_selected_row(Some(0));
434 state_container.set_scroll_offset((0, col_offset));
435 state_container.set_table_selected_row(Some(0));
436
437 let mut nav = state_container.navigation_mut();
439 nav.selected_row = 0;
440 nav.scroll_offset.0 = 0;
441
442 if let Ok(mut vm_borrow) = viewport_manager.try_borrow_mut() {
444 if let Some(ref mut vm) = *vm_borrow {
445 vm.set_crosshair_row(0);
446 vm.set_scroll_offset(0, col_offset);
447 debug!(
448 "StateCoordinator: Reset viewport to first match (row 0) with {} total matches",
449 match_count
450 );
451 }
452 }
453 }
454 }
455
456 debug!(
457 "StateCoordinator: Fuzzy filter applied - {} matches, pattern: '{}'",
458 match_count, pattern
459 );
460
461 (match_count, indices)
462 }
463
464 pub fn reset_table_state_with_refs(
469 state_container: &mut AppStateContainer,
470 viewport_manager: &RefCell<Option<ViewportManager>>,
471 ) {
472 debug!("StateCoordinator::reset_table_state_with_refs: Resetting all table state");
473
474 state_container.navigation_mut().reset();
476 state_container.set_table_selected_row(Some(0));
477 state_container.reset_navigation_state();
478
479 if let Ok(mut vm_borrow) = viewport_manager.try_borrow_mut() {
481 if let Some(ref mut vm) = *vm_borrow {
482 vm.reset_crosshair();
483 debug!("StateCoordinator: Reset ViewportManager crosshair position");
484 }
485 }
486
487 state_container.filter_mut().clear();
489
490 {
492 let mut search = state_container.search_mut();
493 search.pattern.clear();
494 search.current_match = 0;
495 search.matches.clear();
496 search.is_active = false;
497 }
498
499 state_container.clear_fuzzy_filter_state();
501
502 state_container.clear_column_search();
504
505 debug!("StateCoordinator: Table state reset complete");
506 }
507
508 pub fn add_dataview_with_refs(
513 state_container: &mut AppStateContainer,
514 viewport_manager: &RefCell<Option<ViewportManager>>,
515 dataview: DataView,
516 source_name: &str,
517 config: &Config,
518 ) -> Result<(), anyhow::Error> {
519 debug!(
520 "StateCoordinator::add_dataview_with_refs: Adding DataView for '{}'",
521 source_name
522 );
523
524 let buffer_id = state_container.buffers().all_buffers().len() + 1;
526 let mut buffer = crate::buffer::Buffer::new(buffer_id);
527
528 buffer.set_dataview(Some(dataview.clone()));
530
531 let buffer_name = std::path::Path::new(source_name)
533 .file_name()
534 .and_then(|s| s.to_str())
535 .unwrap_or(source_name)
536 .to_string();
537 buffer.set_name(buffer_name.clone());
538
539 buffer.set_case_insensitive(config.behavior.case_insensitive_default);
541 buffer.set_compact_mode(config.display.compact_mode);
542 buffer.set_show_row_numbers(config.display.show_row_numbers);
543
544 debug!(
545 "StateCoordinator: Created buffer '{}' with {} rows, {} columns",
546 buffer_name,
547 dataview.row_count(),
548 dataview.column_count()
549 );
550
551 state_container.buffers_mut().add_buffer(buffer);
553 let new_index = state_container.buffers().all_buffers().len() - 1;
554 state_container.buffers_mut().switch_to(new_index);
555
556 state_container.set_dataview(Some(dataview.clone()));
558
559 *viewport_manager.borrow_mut() = Some(ViewportManager::new(Arc::new(dataview.clone())));
562
563 debug!("StateCoordinator: Created new ViewportManager for DataView");
564
565 let row_count = dataview.row_count();
567 let column_count = dataview.column_count();
568 state_container.update_data_size(row_count, column_count);
569
570 debug!(
571 "StateCoordinator: DataView '{}' successfully added and all state synchronized",
572 buffer_name
573 );
574
575 Ok(())
576 }
577
578 pub fn set_sql_query_with_refs(
583 state_container: &mut AppStateContainer,
584 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
585 parser: &mut HybridParser,
586 table_name: &str,
587 raw_table_name: &str,
588 config: &Config,
589 ) -> String {
590 debug!(
591 "StateCoordinator::set_sql_query_with_refs: Setting query for table '{}'",
592 table_name
593 );
594
595 let auto_query = format!("SELECT * FROM {}", table_name);
597
598 if let Some(dataview) = state_container
600 .buffers()
601 .current()
602 .and_then(|b| b.get_dataview())
603 {
604 let columns = dataview.column_names();
605 parser.update_single_table(table_name.to_string(), columns);
606
607 let display_msg = if raw_table_name != table_name {
609 format!(
610 "Loaded '{}' as table '{}' with {} columns. Query pre-populated.",
611 raw_table_name,
612 table_name,
613 dataview.column_count()
614 )
615 } else {
616 format!(
617 "Loaded table '{}' with {} columns. Query pre-populated.",
618 table_name,
619 dataview.column_count()
620 )
621 };
622 state_container.set_status_message(display_msg);
623 }
624
625 let initial_mode = match config.behavior.start_mode.to_lowercase().as_str() {
627 "results" => AppMode::Results,
628 "command" => AppMode::Command,
629 _ => AppMode::Results, };
631
632 Self::sync_mode_with_refs(
634 state_container,
635 shadow_state,
636 initial_mode.clone(),
637 "initial_load_from_config",
638 );
639
640 debug!(
641 "StateCoordinator: SQL query set to '{}', mode set to {:?}",
642 auto_query, initial_mode
643 );
644
645 auto_query
646 }
647
648 pub fn handle_execute_query_with_refs(
651 state_container: &mut AppStateContainer,
652 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
653 query: &str,
654 ) -> Result<bool, anyhow::Error> {
655 debug!(
656 "StateCoordinator::handle_execute_query_with_refs: Processing query '{}'",
657 query
658 );
659
660 let trimmed = query.trim();
661
662 if trimmed.is_empty() {
663 state_container
664 .set_status_message("Empty query - please enter a SQL command".to_string());
665 return Ok(false);
666 }
667
668 if trimmed == ":help" {
670 state_container.set_help_visible(true);
671 Self::sync_mode_with_refs(
672 state_container,
673 shadow_state,
674 AppMode::Help,
675 "help_requested",
676 );
677 state_container.set_status_message("Help Mode - Press ESC to return".to_string());
678 Ok(false)
679 } else if trimmed == ":exit" || trimmed == ":quit" || trimmed == ":q" {
680 Ok(true) } else if trimmed == ":tui" {
682 state_container.set_status_message("Already in TUI mode".to_string());
683 Ok(false)
684 } else {
685 state_container.set_status_message(format!("Processing query: '{}'", trimmed));
687 Ok(false)
688 }
689 }
690
691 pub fn switch_to_results_after_query(&mut self) {
695 self.sync_mode(AppMode::Results, "execute_query_success");
696 }
697
698 pub fn switch_to_results_after_query_with_refs(
700 state_container: &mut AppStateContainer,
701 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
702 ) {
703 Self::sync_mode_with_refs(
704 state_container,
705 shadow_state,
706 AppMode::Results,
707 "execute_query_success",
708 );
709 }
710
711 pub fn apply_filter_search_with_refs(
715 state_container: &mut AppStateContainer,
716 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
717 pattern: &str,
718 ) {
719 debug!(
720 "StateCoordinator::apply_filter_search_with_refs: Applying filter with pattern '{}'",
721 pattern
722 );
723
724 state_container.set_filter_pattern(pattern.to_string());
726 state_container
727 .filter_mut()
728 .set_pattern(pattern.to_string());
729
730 let before_count = state_container
732 .get_buffer_dataview()
733 .map(|v| v.source().row_count())
734 .unwrap_or(0);
735
736 debug!(
737 "StateCoordinator: Filter search - case_insensitive={}, rows_before={}",
738 state_container.is_case_insensitive(),
739 before_count
740 );
741
742 debug!(
746 "StateCoordinator: Filter pattern set to '{}', mode={:?}",
747 pattern,
748 shadow_state.borrow().get_mode()
749 );
750 }
751
752 pub fn apply_fuzzy_filter_search_with_refs(
754 state_container: &mut AppStateContainer,
755 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
756 pattern: &str,
757 ) {
758 debug!(
759 "StateCoordinator::apply_fuzzy_filter_search_with_refs: Applying fuzzy filter with pattern '{}'",
760 pattern
761 );
762
763 let before_count = state_container
764 .get_buffer_dataview()
765 .map(|v| v.source().row_count())
766 .unwrap_or(0);
767
768 state_container.set_fuzzy_filter_pattern(pattern.to_string());
770
771 debug!(
772 "StateCoordinator: Fuzzy filter - rows_before={}, pattern='{}'",
773 before_count, pattern
774 );
775
776 debug!(
780 "StateCoordinator: Fuzzy filter pattern set, mode={:?}",
781 shadow_state.borrow().get_mode()
782 );
783 }
784
785 pub fn apply_column_search_with_refs(
787 state_container: &mut AppStateContainer,
788 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
789 pattern: &str,
790 ) {
791 debug!(
792 "StateCoordinator::apply_column_search_with_refs: Starting column search with pattern '{}'",
793 pattern
794 );
795
796 state_container.start_column_search(pattern.to_string());
798
799 let current_mode = shadow_state.borrow().get_mode();
801 if current_mode != AppMode::ColumnSearch {
802 debug!(
803 "StateCoordinator: WARNING - Mode was {:?}, restoring to ColumnSearch",
804 current_mode
805 );
806 Self::sync_mode_with_refs(
807 state_container,
808 shadow_state,
809 AppMode::ColumnSearch,
810 "column_search_mode_restore",
811 );
812 }
813
814 debug!(
815 "StateCoordinator: Column search started with pattern '{}'",
816 pattern
817 );
818 }
819
820 pub fn start_history_search_with_refs(
824 state_container: &mut AppStateContainer,
825 shadow_state: &RefCell<crate::ui::state::shadow_state::ShadowStateManager>,
826 current_input: String,
827 ) -> (String, usize) {
828 debug!("StateCoordinator::start_history_search_with_refs: Starting history search");
829
830 let mut input_to_use = current_input;
831
832 if shadow_state.borrow().is_in_results_mode() {
834 let last_query = state_container.get_last_query();
835 if !last_query.is_empty() {
836 input_to_use = last_query.clone();
837 debug!(
838 "StateCoordinator: Using last query for history search: '{}'",
839 last_query
840 );
841 }
842
843 state_container.set_mode(AppMode::Command);
845 shadow_state
846 .borrow_mut()
847 .observe_mode_change(AppMode::Command, "history_search_from_results");
848 state_container.set_table_selected_row(None);
849 }
850
851 state_container.start_history_search(input_to_use.clone());
853
854 let match_count = state_container.history_search().matches.len();
859 state_container.set_status_message(format!("History search: {} matches", match_count));
860
861 state_container.set_mode(AppMode::History);
863 shadow_state
864 .borrow_mut()
865 .observe_mode_change(AppMode::History, "history_search_started");
866
867 debug!(
868 "StateCoordinator: History search started with {} matches, mode=History",
869 match_count
870 );
871
872 (input_to_use, match_count)
873 }
874
875 pub fn goto_first_row_with_refs(
879 state_container: &mut AppStateContainer,
880 vim_search_adapter: Option<
881 &RefCell<crate::ui::search::vim_search_adapter::VimSearchAdapter>,
882 >,
883 viewport_manager: Option<&RefCell<Option<ViewportManager>>>,
884 ) {
885 debug!("StateCoordinator::goto_first_row_with_refs: Going to first row");
886
887 state_container.set_table_selected_row(Some(0));
889 state_container.set_scroll_offset((0, 0));
890
891 if let Some(adapter) = vim_search_adapter {
893 let is_navigating = adapter.borrow().is_navigating();
894
895 if is_navigating {
896 if let Some(viewport_ref) = viewport_manager {
897 let mut vim_search_mut = adapter.borrow_mut();
898 let mut viewport_borrow = viewport_ref.borrow_mut();
899 if let Some(ref mut viewport) = *viewport_borrow {
900 if let Some(first_match) = vim_search_mut.reset_to_first_match(viewport) {
901 debug!(
902 "StateCoordinator: Reset vim search to first match at ({}, {})",
903 first_match.row, first_match.col
904 );
905 }
906 }
907 }
908 }
909 }
910 }
911
912 pub fn goto_last_row_with_refs(state_container: &mut AppStateContainer) {
914 debug!("StateCoordinator::goto_last_row_with_refs: Going to last row");
915
916 if let Some(dataview) = state_container.get_buffer_dataview() {
918 let last_row = dataview.row_count().saturating_sub(1);
919 state_container.set_table_selected_row(Some(last_row));
920
921 let scroll_row = last_row.saturating_sub(20); state_container.set_scroll_offset((scroll_row, 0));
925 }
926 }
927
928 pub fn goto_row_with_refs(state_container: &mut AppStateContainer, row: usize) {
930 debug!("StateCoordinator::goto_row_with_refs: Going to row {}", row);
931
932 if let Some(dataview) = state_container.get_buffer_dataview() {
934 let max_row = dataview.row_count().saturating_sub(1);
935 let target_row = row.min(max_row);
936
937 state_container.set_table_selected_row(Some(target_row));
938
939 let current_scroll = state_container.get_scroll_offset().0;
941 if target_row < current_scroll || target_row > current_scroll + 20 {
942 let new_scroll = target_row.saturating_sub(10);
944 state_container.set_scroll_offset((new_scroll, 0));
945 }
946 }
947 }
948
949 pub fn state_container(&self) -> &AppStateContainer {
953 &self.state_container
954 }
955
956 pub fn state_container_mut(&mut self) -> &mut AppStateContainer {
958 &mut self.state_container
959 }
960
961 pub fn current_buffer(&self) -> Option<&Buffer> {
963 self.state_container.buffers().current()
964 }
965
966 pub fn current_buffer_mut(&mut self) -> Option<&mut Buffer> {
968 self.state_container.buffers_mut().current_mut()
969 }
970
971 pub fn buffers(&self) -> &BufferManager {
973 self.state_container.buffers()
974 }
975
976 pub fn buffers_mut(&mut self) -> &mut BufferManager {
978 self.state_container.buffers_mut()
979 }
980
981 pub fn parser(&self) -> &HybridParser {
983 &self.hybrid_parser
984 }
985
986 pub fn parser_mut(&mut self) -> &mut HybridParser {
988 &mut self.hybrid_parser
989 }
990}