dprint_cli_core/logging/
select.rs1use anyhow::bail;
2use anyhow::Result;
3use crossterm::event::Event;
4use crossterm::event::KeyCode;
5
6use crate::logging::Logger;
7use crate::logging::LoggerRefreshItemKind;
8use crate::logging::LoggerTextItem;
9use crate::terminal::read_terminal_event;
10
11struct SelectData<'a> {
12 prompt: &'a str,
13 item_hanging_indent: u16,
14 items: &'a [String],
15 active_index: usize,
16}
17
18pub fn show_select(logger: &Logger, context_name: &str, prompt: &str, item_hanging_indent: u16, items: &[String]) -> Result<usize> {
19 let mut data = SelectData {
20 prompt,
21 item_hanging_indent,
22 items,
23 active_index: 0,
24 };
25
26 loop {
27 let text_items = render_select(&data);
28 logger.set_refresh_item(LoggerRefreshItemKind::Selection, text_items);
29
30 if let Event::Key(key_event) = read_terminal_event()? {
31 match &key_event.code {
32 KeyCode::Up => {
33 if data.active_index == 0 {
34 data.active_index = data.items.len() - 1;
35 } else {
36 data.active_index -= 1;
37 }
38 }
39 KeyCode::Down => {
40 data.active_index = (data.active_index + 1) % data.items.len();
41 }
42 KeyCode::Enter => {
43 break;
44 }
45 KeyCode::Esc => {
46 logger.remove_refresh_item(LoggerRefreshItemKind::Selection);
47 bail!("Selection cancelled.");
48 }
49 _ => {}
50 }
51 } else {
52 }
54 }
55 logger.remove_refresh_item(LoggerRefreshItemKind::Selection);
56
57 logger.log_text_items(
58 &[
59 LoggerTextItem::Text(data.prompt.to_string()),
60 LoggerTextItem::HangingText {
61 text: data.items[data.active_index].to_string(),
62 indent: item_hanging_indent,
63 },
64 ],
65 context_name,
66 crate::terminal::get_terminal_width(),
67 );
68
69 Ok(data.active_index)
70}
71
72fn render_select(data: &SelectData) -> Vec<LoggerTextItem> {
73 let mut result = vec![LoggerTextItem::Text(data.prompt.to_string())];
74
75 for (i, item_text) in data.items.iter().enumerate() {
76 let mut text = String::new();
77 text.push_str(if i == data.active_index { ">" } else { " " });
78 text.push(' ');
79 text.push_str(item_text);
80 result.push(LoggerTextItem::HangingText {
81 text,
82 indent: 2 + data.item_hanging_indent,
83 });
84 }
85
86 result
87}