1use std::{future::Future, pin::Pin};
4
5use reovim_plugin_microscope::{
6 MicroscopeAction, MicroscopeData, MicroscopeItem, Picker, PickerContext, PreviewContent,
7};
8
9#[derive(Debug, Clone)]
11pub struct HelpEntry {
12 pub tag: String,
14 pub description: String,
16 pub content: Vec<String>,
18}
19
20pub struct HelpPicker {
22 entries: Vec<HelpEntry>,
24}
25
26impl HelpPicker {
27 #[must_use]
29 pub fn new() -> Self {
30 Self {
31 entries: default_help_entries(),
32 }
33 }
34
35 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}