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.active_window().is_line_numbers_visible();
40 let line_wrap = self.active_window().is_line_wrap_enabled();
41 let page_view = self.active_window().is_page_view();
42 let file_explorer_visible = self.file_explorer_visible();
43 let file_explorer_focused = self.active_window().is_file_explorer_focused();
44 let mouse_capture = self.active_window_mut().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_buffer = !self
51 .active_window()
52 .buffer_metadata
53 .get(&self.active_buffer())
54 .map(|m| m.synthetic_placeholder)
55 .unwrap_or(false);
56 let has_selection = has_buffer && self.has_active_selection();
57 let can_copy = has_selection
58 || file_explorer_focused
59 || self
60 .file_explorer()
61 .as_ref()
62 .map(|fe| fe.get_selected().is_some())
63 .unwrap_or(false);
64 let can_paste = if file_explorer_focused {
68 self.active_window().file_explorer_clipboard.is_some()
69 } else {
70 has_buffer && self.active_window().file_explorer_clipboard.is_none()
71 };
72 let menu_bar = self.active_window_mut().menu_bar_visible;
73 let vertical_scrollbar = self.config.editor.show_vertical_scrollbar;
74 let horizontal_scrollbar = self.config.editor.show_horizontal_scrollbar;
75
76 let show_hidden = self.active_window().is_file_explorer_showing_hidden();
78 let show_gitignored = self.active_window().is_file_explorer_showing_gitignored();
79
80 let lsp_available = self.active_window().is_lsp_available();
82 let formatter_available = self.active_window().is_formatter_available();
83
84 let session_mode = self.session_mode;
86
87 let scroll_sync = self.active_window().same_buffer_scroll_sync;
89 let has_same_buffer_splits = self.active_window().has_same_buffer_splits();
90
91 let active_keymap: &str = &self.config.active_keybinding_map;
93
94 self.menu_state
96 .context
97 .set(context_keys::HAS_BUFFER, has_buffer)
98 .set(context_keys::KEYMAP_DEFAULT, active_keymap == "default")
99 .set(context_keys::KEYMAP_EMACS, active_keymap == "emacs")
100 .set(context_keys::KEYMAP_VSCODE, active_keymap == "vscode")
101 .set(context_keys::KEYMAP_MACOS_GUI, active_keymap == "macos-gui")
102 .set(context_keys::LINE_NUMBERS, line_numbers)
103 .set(context_keys::LINE_WRAP, line_wrap)
104 .set(context_keys::PAGE_VIEW, page_view)
105 .set(context_keys::COMPOSE_MODE, page_view)
107 .set(context_keys::FILE_EXPLORER, file_explorer_visible)
108 .set(context_keys::FILE_EXPLORER_FOCUSED, file_explorer_focused)
109 .set(context_keys::MOUSE_CAPTURE, mouse_capture)
110 .set(context_keys::MOUSE_HOVER, mouse_hover)
111 .set(context_keys::INLAY_HINTS, inlay_hints)
112 .set(context_keys::LSP_AVAILABLE, lsp_available)
113 .set(context_keys::FILE_EXPLORER_SHOW_HIDDEN, show_hidden)
114 .set(context_keys::FILE_EXPLORER_SHOW_GITIGNORED, show_gitignored)
115 .set(context_keys::HAS_SELECTION, has_selection)
116 .set(context_keys::CAN_COPY, can_copy)
117 .set(context_keys::CAN_PASTE, can_paste)
118 .set(context_keys::MENU_BAR, menu_bar)
119 .set(context_keys::FORMATTER_AVAILABLE, formatter_available)
120 .set(context_keys::SESSION_MODE, session_mode)
121 .set(context_keys::VERTICAL_SCROLLBAR, vertical_scrollbar)
122 .set(context_keys::HORIZONTAL_SCROLLBAR, horizontal_scrollbar)
123 .set(context_keys::SCROLL_SYNC, scroll_sync)
124 .set(context_keys::HAS_SAME_BUFFER_SPLITS, has_same_buffer_splits);
125 }
126}
127
128impl crate::app::window::Window {
129 pub(crate) fn is_line_numbers_visible(&self) -> bool {
131 let (mgr, vs) = self
132 .buffers
133 .splits()
134 .expect("active window must have a populated split layout");
135 vs.get(&mgr.active_split())
136 .map(|vs| vs.show_line_numbers)
137 .unwrap_or(true)
138 }
139
140 pub(crate) fn is_line_wrap_enabled(&self) -> bool {
142 let (mgr, vs) = self
143 .buffers
144 .splits()
145 .expect("active window must have a populated split layout");
146 vs.get(&mgr.active_split())
147 .map(|vs| vs.viewport.line_wrap_enabled)
148 .unwrap_or(false)
149 }
150
151 pub(crate) fn is_page_view(&self) -> bool {
153 let (mgr, vs) = self
154 .buffers
155 .splits()
156 .expect("active window must have a populated split layout");
157 vs.get(&mgr.active_split())
158 .map(|vs| vs.view_mode == crate::state::ViewMode::PageView)
159 .unwrap_or(false)
160 }
161
162 pub(crate) fn is_file_explorer_focused(&self) -> bool {
164 self.key_context == crate::input::keybindings::KeyContext::FileExplorer
165 }
166
167 pub(crate) fn is_file_explorer_showing_hidden(&self) -> bool {
169 self.file_explorer
170 .as_ref()
171 .map(|fe| fe.ignore_patterns().show_hidden())
172 .unwrap_or(false)
173 }
174
175 pub(crate) fn is_file_explorer_showing_gitignored(&self) -> bool {
177 self.file_explorer
178 .as_ref()
179 .map(|fe| fe.ignore_patterns().show_gitignored())
180 .unwrap_or(false)
181 }
182
183 pub(crate) fn is_lsp_available(&self) -> bool {
185 let buffer_id = self.active_buffer();
186
187 if let Some(metadata) = self.buffer_metadata.get(&buffer_id) {
189 if !metadata.lsp_enabled {
190 return false;
191 }
192 } else {
193 return false;
194 }
195
196 self.buffers
198 .get(&buffer_id)
199 .map(|state| self.lsp.is_server_ready(&state.language))
200 .unwrap_or(false)
201 }
202
203 pub(crate) fn has_same_buffer_splits(&self) -> bool {
205 let (mgr, vs) = self
206 .buffers
207 .splits()
208 .expect("active window must have a populated split layout");
209 let active_split = mgr.active_split();
210 let active_buf_id = mgr.buffer_for_split(active_split);
211 if let Some(buf_id) = active_buf_id {
212 vs.keys()
213 .any(|&s| s != active_split && mgr.buffer_for_split(s) == Some(buf_id))
214 } else {
215 false
216 }
217 }
218
219 pub(crate) fn is_formatter_available(&self) -> bool {
221 let buffer_id = self.active_buffer();
222 self.buffers
223 .get(&buffer_id)
224 .and_then(|state| {
225 self.config()
226 .languages
227 .get(&state.language)
228 .and_then(|lc| lc.formatter.as_ref())
229 .map(|_| true)
230 })
231 .unwrap_or(false)
232 }
233}