fresh/app/
toggle_actions.rs1use rust_i18n::t;
10
11use crate::config::Config;
12use crate::config_io::{ConfigLayer, ConfigResolver};
13use crate::input::keybindings::KeybindingResolver;
14use crate::services::lsp::manager::detect_language;
15
16use super::Editor;
17
18impl Editor {
19 pub fn toggle_line_numbers(&mut self) {
21 if let Some(state) = self.buffers.get_mut(&self.active_buffer()) {
22 let currently_shown = state.margins.show_line_numbers;
23 state.margins.set_line_numbers(!currently_shown);
24 if currently_shown {
25 self.set_status_message(t!("toggle.line_numbers_hidden").to_string());
26 } else {
27 let total_lines = state.buffer.line_count().unwrap_or(1);
29 state.margins.update_width_for_buffer(total_lines);
30 self.set_status_message(t!("toggle.line_numbers_shown").to_string());
31 }
32 }
33 }
34
35 pub fn toggle_debug_highlights(&mut self) {
38 if let Some(state) = self.buffers.get_mut(&self.active_buffer()) {
39 state.debug_highlight_mode = !state.debug_highlight_mode;
40 if state.debug_highlight_mode {
41 self.set_status_message(t!("toggle.debug_mode_on").to_string());
42 } else {
43 self.set_status_message(t!("toggle.debug_mode_off").to_string());
44 }
45 }
46 }
47
48 pub fn toggle_menu_bar(&mut self) {
50 self.menu_bar_visible = !self.menu_bar_visible;
51 self.menu_bar_auto_shown = false;
53 if !self.menu_bar_visible {
55 self.menu_state.close_menu();
56 }
57 let status = if self.menu_bar_visible {
58 t!("toggle.menu_bar_shown")
59 } else {
60 t!("toggle.menu_bar_hidden")
61 };
62 self.set_status_message(status.to_string());
63 }
64
65 pub fn toggle_tab_bar(&mut self) {
67 self.tab_bar_visible = !self.tab_bar_visible;
68 let status = if self.tab_bar_visible {
69 t!("toggle.tab_bar_shown")
70 } else {
71 t!("toggle.tab_bar_hidden")
72 };
73 self.set_status_message(status.to_string());
74 }
75
76 pub fn tab_bar_visible(&self) -> bool {
78 self.tab_bar_visible
79 }
80
81 pub fn reset_buffer_settings(&mut self) {
83 let buffer_id = self.active_buffer();
84
85 let file_path = self
87 .buffer_metadata
88 .get(&buffer_id)
89 .and_then(|m| m.file_path().cloned());
90
91 let (tab_size, use_tabs, show_whitespace_tabs) = if let Some(path) = &file_path {
93 if let Some(language) = detect_language(path, &self.config.languages) {
94 if let Some(lang_config) = self.config.languages.get(&language) {
95 (
96 lang_config.tab_size.unwrap_or(self.config.editor.tab_size),
97 lang_config.use_tabs,
98 lang_config.show_whitespace_tabs,
99 )
100 } else {
101 (self.config.editor.tab_size, false, true)
102 }
103 } else {
104 (self.config.editor.tab_size, false, true)
105 }
106 } else {
107 (self.config.editor.tab_size, false, true)
108 };
109
110 if let Some(state) = self.buffers.get_mut(&buffer_id) {
112 state.tab_size = tab_size;
113 state.use_tabs = use_tabs;
114 state.show_whitespace_tabs = show_whitespace_tabs;
115 }
116
117 self.set_status_message(t!("toggle.buffer_settings_reset").to_string());
118 }
119
120 pub fn toggle_mouse_capture(&mut self) {
122 use std::io::stdout;
123
124 self.mouse_enabled = !self.mouse_enabled;
125
126 if self.mouse_enabled {
127 let _ = crossterm::execute!(stdout(), crossterm::event::EnableMouseCapture);
128 self.set_status_message(t!("toggle.mouse_capture_enabled").to_string());
129 } else {
130 let _ = crossterm::execute!(stdout(), crossterm::event::DisableMouseCapture);
131 self.set_status_message(t!("toggle.mouse_capture_disabled").to_string());
132 }
133 }
134
135 pub fn is_mouse_enabled(&self) -> bool {
137 self.mouse_enabled
138 }
139
140 pub fn toggle_mouse_hover(&mut self) {
142 self.config.editor.mouse_hover_enabled = !self.config.editor.mouse_hover_enabled;
143
144 if self.config.editor.mouse_hover_enabled {
145 self.set_status_message(t!("toggle.mouse_hover_enabled").to_string());
146 } else {
147 self.mouse_state.lsp_hover_state = None;
149 self.mouse_state.lsp_hover_request_sent = false;
150 self.set_status_message(t!("toggle.mouse_hover_disabled").to_string());
151 }
152 }
153
154 pub fn is_mouse_hover_enabled(&self) -> bool {
156 self.config.editor.mouse_hover_enabled
157 }
158
159 pub fn set_gpm_active(&mut self, active: bool) {
165 self.gpm_active = active;
166 }
167
168 pub fn toggle_inlay_hints(&mut self) {
170 self.config.editor.enable_inlay_hints = !self.config.editor.enable_inlay_hints;
171
172 if self.config.editor.enable_inlay_hints {
173 self.request_inlay_hints_for_active_buffer();
175 self.set_status_message(t!("toggle.inlay_hints_enabled").to_string());
176 } else {
177 for state in self.buffers.values_mut() {
179 state.virtual_texts.clear(&mut state.marker_list);
180 }
181 self.set_status_message(t!("toggle.inlay_hints_disabled").to_string());
182 }
183 }
184
185 pub fn dump_config(&mut self) {
187 if let Err(e) = self.filesystem.create_dir_all(&self.dir_context.config_dir) {
189 self.set_status_message(
190 t!("error.config_dir_failed", error = e.to_string()).to_string(),
191 );
192 return;
193 }
194
195 let config_path = self.dir_context.config_path();
196 let resolver = ConfigResolver::new(self.dir_context.clone(), self.working_dir.clone());
197
198 match resolver.save_to_layer(&self.config, ConfigLayer::User) {
200 Ok(()) => {
201 match self.open_file(&config_path) {
203 Ok(_buffer_id) => {
204 self.set_status_message(
205 t!("config.saved", path = config_path.display().to_string())
206 .to_string(),
207 );
208 }
209 Err(e) => {
210 self.set_status_message(
211 t!("config.saved_failed_open", error = e.to_string()).to_string(),
212 );
213 }
214 }
215 }
216 Err(e) => {
217 self.set_status_message(
218 t!("error.config_save_failed", error = e.to_string()).to_string(),
219 );
220 }
221 }
222 }
223
224 pub fn save_config(&self) -> Result<(), String> {
228 self.filesystem
230 .create_dir_all(&self.dir_context.config_dir)
231 .map_err(|e| format!("Failed to create config directory: {}", e))?;
232
233 let resolver = ConfigResolver::new(self.dir_context.clone(), self.working_dir.clone());
234 resolver
235 .save_to_layer(&self.config, ConfigLayer::User)
236 .map_err(|e| format!("Failed to save config: {}", e))
237 }
238
239 pub fn reload_config(&mut self) {
245 let old_theme = self.config.theme.clone();
246 self.config = Config::load_with_layers(&self.dir_context, &self.working_dir);
247
248 if old_theme != self.config.theme {
250 if let Some(theme) = self.theme_registry.get_cloned(&self.config.theme) {
251 self.theme = theme;
252 tracing::info!("Theme changed to '{}'", self.config.theme.0);
253 } else {
254 tracing::error!("Theme '{}' not found", self.config.theme.0);
255 }
256 }
257
258 self.keybindings = KeybindingResolver::new(&self.config);
260
261 if let Some(ref mut lsp) = self.lsp {
263 for (language, lsp_config) in &self.config.lsp {
264 lsp.set_language_config(language.clone(), lsp_config.clone());
265 }
266 }
267
268 let config_path = Config::find_config_path(&self.working_dir);
270 self.emit_event(
271 "config_changed",
272 serde_json::json!({
273 "path": config_path.map(|p| p.to_string_lossy().into_owned()),
274 }),
275 );
276 }
277
278 pub fn reload_themes(&mut self) {
283 use crate::view::theme::ThemeLoader;
284
285 let theme_loader = ThemeLoader::new();
286 self.theme_registry = theme_loader.load_all();
287
288 if let Some(theme) = self.theme_registry.get_cloned(&self.config.theme) {
290 self.theme = theme;
291 }
292
293 tracing::info!(
294 "Theme registry reloaded ({} themes)",
295 self.theme_registry.len()
296 );
297
298 self.emit_event("themes_changed", serde_json::json!({}));
300 }
301}