1pub struct List<'a, T> {
2 message: &'a str,
3 selection_list: Vec<(&'a str, T)>,
4 term_data: TermData,
5}
6
7impl<'a, T> List<'a, T> {
8 pub fn new(message: &'a str) -> Self {
9 Self {
10 message,
11 selection_list: Vec::new(),
12 term_data: TermData::new(),
13 }
14 }
15
16 pub fn add_item(mut self, selection_name: &'a str, item: T) -> Self {
17 self.selection_list.push((selection_name, item));
18 self
19 }
20
21 pub fn inquire(mut self) -> Result<T, InquiryMessage> {
22 if !self.term_data.enable_raw() {
23 return Err(InquiryMessage::TermEnableRawErr);
24 }
25
26 AnsiBuilder::new()
27 .text("[")
28 .color()
29 .fg()
30 .bright_green()
31 .text("?")
32 .reset_attributes()
33 .text("] ")
34 .text(&self.message)
35 .cursor()
36 .save()
37 .cursor()
38 .hide()
39 .println();
40 let mut selected_index = 0;
41
42 let list_len = self.selection_list.len();
43 for _ in 0..list_len - 1 {
44 println!();
45 }
46
47 loop {
48 AnsiBuilder::new().cursor().up(list_len).print();
49
50 for i in 0..list_len {
51 AnsiBuilder::new()
52 .text("\n\r")
53 .erase_line(ClearMode::EntireLine)
54 .print();
55
56 if i == selected_index {
57 AnsiBuilder::new()
58 .color()
59 .fg()
60 .bright_green()
61 .style()
62 .bold()
63 .text(" → ")
64 .reset_attributes()
65 .text(&self.selection_list[i].0)
66 .print();
67 continue;
68 }
69
70 AnsiBuilder::new()
71 .text(" ")
72 .color()
73 .fg()
74 .gray()
75 .text(&self.selection_list[i].0)
76 .reset_attributes()
77 .print();
78 }
79
80 match stdout().lock().flush() {
81 Ok(..) => {}
82 Err(..) => return Err(InquiryMessage::FlushLockErr),
83 };
84
85 let key = Keys::from(stdin());
86
87 match key {
88 Keys::Up => {
89 if selected_index > 0 {
90 selected_index -= 1
91 }
92 }
93 Keys::Down => {
94 if selected_index < self.selection_list.len() - 1 {
95 selected_index += 1;
96 }
97 }
98 Keys::Enter => {
99 let (name, value) = self.selection_list.remove(selected_index);
100
101 AnsiBuilder::new()
102 .cursor()
103 .restore()
104 .color()
105 .fg()
106 .blue()
107 .text(&format!(" {}", name))
108 .reset_attributes()
109 .println()
110 .cursor()
111 .save()
112 .erase_in_display(EraseMode::CursorToEnd)
113 .cursor()
114 .restore()
115 .cursor()
116 .show()
117 .print();
118
119 if !self.term_data.disable_raw() {
120 return Err(InquiryMessage::TermDisableRawErr);
121 }
122
123 return Ok(value);
124 }
125 Keys::CtrlC | Keys::CtrlZ => {
126 AnsiBuilder::new().cursor().show().print();
127
128 if !self.term_data.disable_raw() {
129 return Err(InquiryMessage::TermDisableRawErr);
130 }
131
132 return Err(InquiryMessage::CloseRequested);
133 }
134 _ => { }
139 }
140 }
141 }
142}
143
144use std::io::{stdin, stdout, Write};
145
146use ansi_builder::{AnsiBuilder, ClearMode, EraseMode};
147
148use crate::{term_data::TermData, InquiryMessage, Keys};