fresh/app/
menu_context.rs1use super::Editor;
9use crate::view::ui::context_keys;
10
11impl Editor {
12 pub fn menu_context(&self) -> crate::view::ui::MenuContext {
18 self.menu_state.context.clone()
19 }
20
21 pub fn expanded_menu_definitions(&self) -> Vec<fresh_core::menu::Menu> {
25 use crate::config::{MenuConfig, MenuExt};
26
27 let mut menus = MenuConfig::translated_menus();
28 let themes_dir = self.menu_state.themes_dir.clone();
29 for menu in &mut menus {
30 menu.expand_dynamic_items(&themes_dir);
31 }
32 menus
33 }
34
35 pub fn update_menu_context(&mut self) {
38 let line_numbers = self.is_line_numbers_visible();
40 let line_wrap = self.is_line_wrap_enabled();
41 let page_view = self.is_page_view();
42 let file_explorer_visible = self.file_explorer_visible;
43 let file_explorer_focused = self.is_file_explorer_focused();
44 let mouse_capture = self.mouse_enabled;
45 let mouse_hover = self.config.editor.mouse_hover_enabled;
46 let inlay_hints = self.config.editor.enable_inlay_hints;
47 let has_selection = self.has_active_selection();
48 let can_copy = has_selection
49 || file_explorer_focused
50 || self
51 .file_explorer
52 .as_ref()
53 .map(|fe| fe.get_selected().is_some())
54 .unwrap_or(false);
55 let can_paste = if file_explorer_focused {
58 self.file_explorer_clipboard.is_some()
59 } else {
60 self.file_explorer_clipboard.is_none()
61 };
62 let menu_bar = self.menu_bar_visible;
63 let vertical_scrollbar = self.config.editor.show_vertical_scrollbar;
64 let horizontal_scrollbar = self.config.editor.show_horizontal_scrollbar;
65
66 let show_hidden = self.is_file_explorer_showing_hidden();
68 let show_gitignored = self.is_file_explorer_showing_gitignored();
69
70 let lsp_available = self.is_lsp_available();
72 let formatter_available = self.is_formatter_available();
73
74 let session_mode = self.session_mode;
76
77 let scroll_sync = self.same_buffer_scroll_sync;
79 let has_same_buffer_splits = self.has_same_buffer_splits();
80
81 let active_keymap: &str = &self.config.active_keybinding_map;
83
84 self.menu_state
86 .context
87 .set(context_keys::KEYMAP_DEFAULT, active_keymap == "default")
88 .set(context_keys::KEYMAP_EMACS, active_keymap == "emacs")
89 .set(context_keys::KEYMAP_VSCODE, active_keymap == "vscode")
90 .set(context_keys::KEYMAP_MACOS_GUI, active_keymap == "macos-gui")
91 .set(context_keys::LINE_NUMBERS, line_numbers)
92 .set(context_keys::LINE_WRAP, line_wrap)
93 .set(context_keys::PAGE_VIEW, page_view)
94 .set(context_keys::COMPOSE_MODE, page_view)
96 .set(context_keys::FILE_EXPLORER, file_explorer_visible)
97 .set(context_keys::FILE_EXPLORER_FOCUSED, file_explorer_focused)
98 .set(context_keys::MOUSE_CAPTURE, mouse_capture)
99 .set(context_keys::MOUSE_HOVER, mouse_hover)
100 .set(context_keys::INLAY_HINTS, inlay_hints)
101 .set(context_keys::LSP_AVAILABLE, lsp_available)
102 .set(context_keys::FILE_EXPLORER_SHOW_HIDDEN, show_hidden)
103 .set(context_keys::FILE_EXPLORER_SHOW_GITIGNORED, show_gitignored)
104 .set(context_keys::HAS_SELECTION, has_selection)
105 .set(context_keys::CAN_COPY, can_copy)
106 .set(context_keys::CAN_PASTE, can_paste)
107 .set(context_keys::MENU_BAR, menu_bar)
108 .set(context_keys::FORMATTER_AVAILABLE, formatter_available)
109 .set(context_keys::SESSION_MODE, session_mode)
110 .set(context_keys::VERTICAL_SCROLLBAR, vertical_scrollbar)
111 .set(context_keys::HORIZONTAL_SCROLLBAR, horizontal_scrollbar)
112 .set(context_keys::SCROLL_SYNC, scroll_sync)
113 .set(context_keys::HAS_SAME_BUFFER_SPLITS, has_same_buffer_splits);
114 }
115
116 fn is_line_numbers_visible(&self) -> bool {
118 let active_split = self.split_manager.active_split();
119 self.split_view_states
120 .get(&active_split)
121 .map(|vs| vs.show_line_numbers)
122 .unwrap_or(true)
123 }
124
125 fn is_line_wrap_enabled(&self) -> bool {
127 let active_split = self.split_manager.active_split();
128 self.split_view_states
129 .get(&active_split)
130 .map(|vs| vs.viewport.line_wrap_enabled)
131 .unwrap_or(false)
132 }
133
134 fn is_page_view(&self) -> bool {
136 let active_split = self.split_manager.active_split();
137 self.split_view_states
138 .get(&active_split)
139 .map(|vs| vs.view_mode == crate::state::ViewMode::PageView)
140 .unwrap_or(false)
141 }
142
143 fn is_file_explorer_focused(&self) -> bool {
145 self.key_context == crate::input::keybindings::KeyContext::FileExplorer
146 }
147
148 fn is_file_explorer_showing_hidden(&self) -> bool {
150 self.file_explorer
151 .as_ref()
152 .map(|fe| fe.ignore_patterns().show_hidden())
153 .unwrap_or(false)
154 }
155
156 fn is_file_explorer_showing_gitignored(&self) -> bool {
158 self.file_explorer
159 .as_ref()
160 .map(|fe| fe.ignore_patterns().show_gitignored())
161 .unwrap_or(false)
162 }
163
164 fn is_lsp_available(&self) -> bool {
166 let buffer_id = self.active_buffer();
167
168 if let Some(metadata) = self.buffer_metadata.get(&buffer_id) {
170 if !metadata.lsp_enabled {
171 return false;
172 }
173 } else {
174 return false;
175 }
176
177 self.buffers
179 .get(&buffer_id)
180 .and_then(|state| {
181 self.lsp
182 .as_ref()
183 .map(|lsp| lsp.is_server_ready(&state.language))
184 })
185 .unwrap_or(false)
186 }
187
188 fn has_same_buffer_splits(&self) -> bool {
190 let active_split = self.split_manager.active_split();
191 let active_buf_id = self.split_manager.buffer_for_split(active_split);
192 if let Some(buf_id) = active_buf_id {
193 self.split_view_states.keys().any(|&s| {
194 s != active_split && self.split_manager.buffer_for_split(s) == Some(buf_id)
195 })
196 } else {
197 false
198 }
199 }
200
201 fn is_formatter_available(&self) -> bool {
203 let buffer_id = self.active_buffer();
204
205 self.buffers
207 .get(&buffer_id)
208 .and_then(|state| {
209 self.config
210 .languages
211 .get(&state.language)
212 .and_then(|lc| lc.formatter.as_ref())
213 .map(|_| true)
214 })
215 .unwrap_or(false)
216 }
217}