Skip to main content

fresh/app/
help_actions.rs

1//! Help-buffer orchestrators.
2//!
3//! `open_help_manual` and `open_keyboard_shortcuts` create read-only
4//! virtual buffers populated with the manual text or keybinding listing.
5//! Both check for an existing help buffer first to avoid duplicates.
6//! All bodies live on `impl Window` — they operate on this window's
7//! buffer storage and use window-side `create_virtual_buffer` +
8//! `set_active_buffer`.
9
10use super::help;
11use crate::app::window::Window;
12
13impl Window {
14    /// Open the built-in help manual in a read-only buffer.
15    ///
16    /// If a help manual buffer already exists, switch to it instead of
17    /// creating a new one.
18    pub fn open_help_manual(&mut self) {
19        // Check if help buffer already exists.
20        let existing_buffer = self
21            .buffer_metadata
22            .iter()
23            .find(|(_, m)| m.display_name == help::HELP_MANUAL_BUFFER_NAME)
24            .map(|(id, _)| *id);
25
26        if let Some(buffer_id) = existing_buffer {
27            self.set_active_buffer(buffer_id);
28            return;
29        }
30
31        // Create new help buffer with "special" mode (has 'q' to close).
32        let buffer_id = self.create_virtual_buffer(
33            help::HELP_MANUAL_BUFFER_NAME.to_string(),
34            "special".to_string(),
35            true,
36        );
37
38        if let Some(state) = self.buffers.get_mut(&buffer_id) {
39            state.buffer.insert(0, help::HELP_MANUAL_CONTENT);
40            state.buffer.clear_modified();
41            state.editing_disabled = true;
42            state.margins.configure_for_line_numbers(false);
43        }
44
45        self.set_active_buffer(buffer_id);
46    }
47
48    /// Open the keyboard shortcuts viewer in a read-only buffer.
49    ///
50    /// If a keyboard shortcuts buffer already exists, switch to it
51    /// instead of creating a new one. The shortcuts are dynamically
52    /// generated from the current keybindings configuration.
53    pub fn open_keyboard_shortcuts(&mut self) {
54        let existing_buffer = self
55            .buffer_metadata
56            .iter()
57            .find(|(_, m)| m.display_name == help::KEYBOARD_SHORTCUTS_BUFFER_NAME)
58            .map(|(id, _)| *id);
59
60        if let Some(buffer_id) = existing_buffer {
61            self.set_active_buffer(buffer_id);
62            return;
63        }
64
65        // Get all keybindings from this window's resources.
66        let bindings = self
67            .resources
68            .keybindings
69            .read()
70            .unwrap()
71            .get_all_bindings();
72
73        // Format the keybindings as readable text.
74        let mut content = String::from("Keyboard Shortcuts\n");
75        content.push_str("==================\n\n");
76        content.push_str("Press 'q' to close this buffer.\n\n");
77
78        let mut current_context = String::new();
79        for (key, action) in &bindings {
80            let (context, action_name) = if let Some(bracket_end) = action.find("] ") {
81                let ctx = &action[1..bracket_end];
82                let name = &action[bracket_end + 2..];
83                (ctx.to_string(), name.to_string())
84            } else {
85                ("Normal".to_string(), action.clone())
86            };
87
88            if context != current_context {
89                if !current_context.is_empty() {
90                    content.push('\n');
91                }
92                content.push_str(&format!("── {} Mode ──\n\n", context));
93                current_context = context;
94            }
95
96            content.push_str(&format!("  {:20} {}\n", key, action_name));
97        }
98
99        let buffer_id = self.create_virtual_buffer(
100            help::KEYBOARD_SHORTCUTS_BUFFER_NAME.to_string(),
101            "special".to_string(),
102            true,
103        );
104
105        if let Some(state) = self.buffers.get_mut(&buffer_id) {
106            state.buffer.insert(0, &content);
107            state.buffer.clear_modified();
108            state.editing_disabled = true;
109            state.margins.configure_for_line_numbers(false);
110        }
111
112        self.set_active_buffer(buffer_id);
113    }
114}