Skip to main content

fresh/app/
menu_context.rs

1//! Menu context computation.
2//!
3//! This module provides methods to compute menu context values that determine
4//! when menu items and commands should be enabled or disabled. Each context
5//! value has a dedicated method that encapsulates the logic for checking
6//! whether that feature is available.
7
8use super::Editor;
9use crate::services::lsp::manager::detect_language;
10use crate::view::ui::context_keys;
11
12impl Editor {
13    /// Update all menu context values based on current editor state.
14    /// This should be called before rendering the menu bar.
15    pub fn update_menu_context(&mut self) {
16        // Simple state lookups
17        let line_numbers = self.is_line_numbers_visible();
18        let line_wrap = self.is_line_wrap_enabled();
19        let compose_mode = self.is_compose_mode();
20        let file_explorer_visible = self.file_explorer_visible;
21        let file_explorer_focused = self.is_file_explorer_focused();
22        let mouse_capture = self.mouse_enabled;
23        let mouse_hover = self.config.editor.mouse_hover_enabled;
24        let inlay_hints = self.config.editor.enable_inlay_hints;
25        let has_selection = self.has_active_selection();
26        let menu_bar = self.menu_bar_visible;
27
28        // File explorer state
29        let show_hidden = self.is_file_explorer_showing_hidden();
30        let show_gitignored = self.is_file_explorer_showing_gitignored();
31
32        // Language-dependent context values
33        let lsp_available = self.is_lsp_available();
34        let formatter_available = self.is_formatter_available();
35
36        // Apply all context values
37        self.menu_state
38            .context
39            .set(context_keys::LINE_NUMBERS, line_numbers)
40            .set(context_keys::LINE_WRAP, line_wrap)
41            .set(context_keys::COMPOSE_MODE, compose_mode)
42            .set(context_keys::FILE_EXPLORER, file_explorer_visible)
43            .set(context_keys::FILE_EXPLORER_FOCUSED, file_explorer_focused)
44            .set(context_keys::MOUSE_CAPTURE, mouse_capture)
45            .set(context_keys::MOUSE_HOVER, mouse_hover)
46            .set(context_keys::INLAY_HINTS, inlay_hints)
47            .set(context_keys::LSP_AVAILABLE, lsp_available)
48            .set(context_keys::FILE_EXPLORER_SHOW_HIDDEN, show_hidden)
49            .set(context_keys::FILE_EXPLORER_SHOW_GITIGNORED, show_gitignored)
50            .set(context_keys::HAS_SELECTION, has_selection)
51            .set(context_keys::MENU_BAR, menu_bar)
52            .set(context_keys::FORMATTER_AVAILABLE, formatter_available);
53    }
54
55    /// Check if line numbers are visible in the active buffer.
56    fn is_line_numbers_visible(&self) -> bool {
57        self.buffers
58            .get(&self.active_buffer())
59            .map(|state| state.margins.show_line_numbers)
60            .unwrap_or(true)
61    }
62
63    /// Check if line wrap is enabled in the active split.
64    fn is_line_wrap_enabled(&self) -> bool {
65        let active_split = self.split_manager.active_split();
66        self.split_view_states
67            .get(&active_split)
68            .map(|vs| vs.viewport.line_wrap_enabled)
69            .unwrap_or(false)
70    }
71
72    /// Check if compose mode is active in the current buffer.
73    fn is_compose_mode(&self) -> bool {
74        self.buffers
75            .get(&self.active_buffer())
76            .map(|state| state.view_mode == crate::state::ViewMode::Compose)
77            .unwrap_or(false)
78    }
79
80    /// Check if the file explorer is currently focused.
81    fn is_file_explorer_focused(&self) -> bool {
82        self.key_context == crate::input::keybindings::KeyContext::FileExplorer
83    }
84
85    /// Check if the file explorer is showing hidden files.
86    fn is_file_explorer_showing_hidden(&self) -> bool {
87        self.file_explorer
88            .as_ref()
89            .map(|fe| fe.ignore_patterns().show_hidden())
90            .unwrap_or(false)
91    }
92
93    /// Check if the file explorer is showing gitignored files.
94    fn is_file_explorer_showing_gitignored(&self) -> bool {
95        self.file_explorer
96            .as_ref()
97            .map(|fe| fe.ignore_patterns().show_gitignored())
98            .unwrap_or(false)
99    }
100
101    /// Check if an LSP server is available and ready for the current buffer's language.
102    fn is_lsp_available(&self) -> bool {
103        self.buffer_metadata
104            .get(&self.active_buffer())
105            .and_then(|metadata| {
106                if !metadata.lsp_enabled {
107                    return None;
108                }
109                metadata.file_path().and_then(|path| {
110                    detect_language(path, &self.config.languages).and_then(|language| {
111                        self.lsp.as_ref().map(|lsp| lsp.is_server_ready(&language))
112                    })
113                })
114            })
115            .unwrap_or(false)
116    }
117
118    /// Check if a formatter is configured for the current buffer's language.
119    fn is_formatter_available(&self) -> bool {
120        self.buffer_metadata
121            .get(&self.active_buffer())
122            .and_then(|metadata| {
123                metadata.file_path().and_then(|path| {
124                    detect_language(path, &self.config.languages).and_then(|language| {
125                        self.config
126                            .languages
127                            .get(&language)
128                            .and_then(|lc| lc.formatter.as_ref())
129                            .map(|_| true)
130                    })
131                })
132            })
133            .unwrap_or(false)
134    }
135}