reovim_plugin_pickers/
help.rs

1//! Help tags picker implementation
2
3use std::{future::Future, pin::Pin};
4
5use reovim_plugin_microscope::{
6    MicroscopeAction, MicroscopeData, MicroscopeItem, Picker, PickerContext, PreviewContent,
7};
8
9/// Help entry
10#[derive(Debug, Clone)]
11pub struct HelpEntry {
12    /// Tag name
13    pub tag: String,
14    /// Brief description
15    pub description: String,
16    /// Full help content
17    pub content: Vec<String>,
18}
19
20/// Picker for help tags
21pub struct HelpPicker {
22    /// Available help entries
23    entries: Vec<HelpEntry>,
24}
25
26impl HelpPicker {
27    /// Create a new help picker
28    #[must_use]
29    pub fn new() -> Self {
30        Self {
31            entries: default_help_entries(),
32        }
33    }
34
35    /// Set help entries
36    pub fn set_entries(&mut self, entries: Vec<HelpEntry>) {
37        self.entries = entries;
38    }
39}
40
41impl Default for HelpPicker {
42    fn default() -> Self {
43        Self::new()
44    }
45}
46
47fn default_help_entries() -> Vec<HelpEntry> {
48    vec![
49        HelpEntry {
50            tag: "modes".to_string(),
51            description: "Editor modes (Normal, Insert, Visual, Command)".to_string(),
52            content: vec![
53                "MODES".to_string(),
54                "=====".to_string(),
55                String::new(),
56                "Normal Mode: Navigate and edit text".to_string(),
57                "  - Press 'i' to enter Insert mode".to_string(),
58                "  - Press 'v' to enter Visual mode".to_string(),
59                "  - Press ':' to enter Command mode".to_string(),
60                String::new(),
61                "Insert Mode: Insert text".to_string(),
62                "  - Press Escape to return to Normal mode".to_string(),
63                String::new(),
64                "Visual Mode: Select text".to_string(),
65                "  - Press 'y' to yank (copy)".to_string(),
66                "  - Press 'd' to delete".to_string(),
67                "  - Press Escape to return to Normal mode".to_string(),
68                String::new(),
69                "Command Mode: Execute commands".to_string(),
70                "  - :w - Write file".to_string(),
71                "  - :q - Quit".to_string(),
72                "  - :wq - Write and quit".to_string(),
73            ],
74        },
75        HelpEntry {
76            tag: "motions".to_string(),
77            description: "Cursor movement commands".to_string(),
78            content: vec![
79                "MOTIONS".to_string(),
80                "=======".to_string(),
81                String::new(),
82                "h, j, k, l     - Move left, down, up, right".to_string(),
83                "w              - Move to next word".to_string(),
84                "b              - Move to previous word".to_string(),
85                "e              - Move to end of word".to_string(),
86                "0              - Move to start of line".to_string(),
87                "$              - Move to end of line".to_string(),
88                "gg             - Move to first line".to_string(),
89                "G              - Move to last line".to_string(),
90            ],
91        },
92        HelpEntry {
93            tag: "microscope".to_string(),
94            description: "Microscope fuzzy finder".to_string(),
95            content: vec![
96                "MICROSCOPE".to_string(),
97                "=========".to_string(),
98                String::new(),
99                "Open Microscope:".to_string(),
100                "  <Space>ff    - Find files".to_string(),
101                "  <Space>fb    - Find buffers".to_string(),
102                "  <Space>fg    - Live grep".to_string(),
103                "  <Space>fr    - Recent files".to_string(),
104                "  <Space>fc    - Command palette".to_string(),
105                "  <Space>fh    - Help tags".to_string(),
106                "  <Space>fk    - Keymaps".to_string(),
107                String::new(),
108                "Navigation:".to_string(),
109                "  C-n, Down    - Next item".to_string(),
110                "  C-p, Up      - Previous item".to_string(),
111                "  Enter        - Confirm selection".to_string(),
112                "  Escape       - Close".to_string(),
113            ],
114        },
115        HelpEntry {
116            tag: "editing".to_string(),
117            description: "Text editing commands".to_string(),
118            content: vec![
119                "EDITING".to_string(),
120                "=======".to_string(),
121                String::new(),
122                "Insert mode:".to_string(),
123                "  i            - Insert before cursor".to_string(),
124                "  a            - Insert after cursor".to_string(),
125                "  A            - Insert at end of line".to_string(),
126                "  o            - Open line below".to_string(),
127                "  O            - Open line above".to_string(),
128                String::new(),
129                "Delete:".to_string(),
130                "  x            - Delete character".to_string(),
131                "  dd           - Delete line".to_string(),
132                "  d{motion}    - Delete with motion".to_string(),
133                String::new(),
134                "Clipboard:".to_string(),
135                "  yy           - Yank (copy) line".to_string(),
136                "  p            - Paste after".to_string(),
137                "  P            - Paste before".to_string(),
138            ],
139        },
140    ]
141}
142
143impl Picker for HelpPicker {
144    fn name(&self) -> &'static str {
145        "help"
146    }
147
148    fn title(&self) -> &'static str {
149        "Help Tags"
150    }
151
152    fn prompt(&self) -> &'static str {
153        "Help> "
154    }
155
156    fn fetch(
157        &self,
158        _ctx: &PickerContext,
159    ) -> Pin<Box<dyn Future<Output = Vec<MicroscopeItem>> + Send + '_>> {
160        Box::pin(async move {
161            self.entries
162                .iter()
163                .map(|entry| {
164                    MicroscopeItem::new(
165                        &entry.tag,
166                        &entry.tag,
167                        MicroscopeData::HelpTag(entry.tag.clone()),
168                        "help",
169                    )
170                    .with_detail(&entry.description)
171                    .with_icon('?')
172                })
173                .collect()
174        })
175    }
176
177    fn on_select(&self, item: &MicroscopeItem) -> MicroscopeAction {
178        match &item.data {
179            MicroscopeData::HelpTag(tag) => MicroscopeAction::ShowHelp(tag.clone()),
180            _ => MicroscopeAction::Nothing,
181        }
182    }
183
184    fn preview(
185        &self,
186        item: &MicroscopeItem,
187        _ctx: &PickerContext,
188    ) -> Pin<Box<dyn Future<Output = Option<PreviewContent>> + Send + '_>> {
189        let tag = match &item.data {
190            MicroscopeData::HelpTag(t) => t.clone(),
191            _ => return Box::pin(async { None }),
192        };
193
194        let content = self
195            .entries
196            .iter()
197            .find(|e| e.tag == tag)
198            .map(|e| e.content.clone());
199
200        Box::pin(async move { content.map(PreviewContent::new) })
201    }
202}