1use crossterm::{
2 cursor::{Hide, MoveLeft, MoveRight, MoveUp, Show},
3 event::{self, Event, KeyCode, KeyEvent},
4 execute,
5 style::{Color, Print, ResetColor, SetForegroundColor},
6 terminal::{disable_raw_mode, enable_raw_mode},
7};
8use unicode_segmentation::UnicodeSegmentation;
9
10use std::io::stdout;
11use std::{thread, time};
12
13pub fn select_from_list(list: &[String], selected: Option<usize>) -> usize {
21 let mut selection = selected.unwrap_or(0);
22
23 let color = get_color();
25
26 execute!(stdout(), Hide).expect("Failed to write hide cursor");
28
29 enable_raw_mode().expect("Failed to enable raw mode");
31
32 loop {
33 write_list(&list, selection, color);
35
36 if let Event::Key(KeyEvent { code, .. }) = event::read().expect("Failed to read event") {
38 match code {
39 KeyCode::Esc => {
40 execute!(stdout(), Show).expect("Failed to write show cursor");
42 disable_raw_mode().expect("Failed to enable raw mode");
44 std::process::exit(0)
46 }
47 KeyCode::Enter => break,
48 KeyCode::Up => {
49 if selection > 0 {
50 selection -= 1;
51 }
52 }
53 KeyCode::Down => {
54 if selection < (list.len() - 1) {
55 selection += 1;
56 }
57 }
58 _ => {}
59 }
60 }
61
62 clear_list(&list);
64
65 thread::sleep(time::Duration::from_millis(50));
66 }
67
68 execute!(stdout(), Show).expect("Failed to write show cursor");
70 disable_raw_mode().expect("Failed to enable raw mode");
72
73 selection
74}
75
76pub fn write_column(first: String, second: String, offset: Option<usize>) {
82 let offset = offset.unwrap_or(20);
84 let diff = offset - first.graphemes(true).count();
85
86 execute!(stdout(), MoveLeft(1), Print(first)).expect("Failed to write first column");
87 execute!(
88 stdout(),
89 MoveRight(diff as u16),
90 Print(format!("{}\n\r", second))
91 )
92 .expect("Failed to write second column");
93}
94
95fn write_list(list: &[String], selection: usize, color: Color) {
97 for (i, item) in list.iter().enumerate() {
99 if i == selection {
100 execute!(
101 stdout(),
102 SetForegroundColor(color),
103 Print(format!("{}\n\r", item)),
104 ResetColor
105 )
106 .expect("Failed to write list");
107 } else {
108 execute!(stdout(), ResetColor, Print(format!("{}\n\r", item))).expect("Failed to write list");
109 }
110 }
111
112 execute!(stdout(), ResetColor).expect("Failed to write reset color");
114}
115
116fn clear_list(list: &[String]) {
118 for _ in list {
120 execute!(stdout(), MoveUp(1)).expect("Failed to write cursor up");
121 }
122}
123
124fn get_color() -> Color {
125 let conf = crate::config::get_gut_config();
126
127 let selected = match conf.get("color") {
128 Some(color) => color.to_string(),
129 None => "Red".to_string(),
130 };
131
132 if selected.contains("Black") {
133 return Color::Black;
134 } else if selected.contains("Red") {
135 return Color::Red;
136 } else if selected.contains("Green") {
137 return Color::Green;
138 } else if selected.contains("Yellow") {
139 return Color::Yellow;
140 } else if selected.contains("Blue") {
141 return Color::Blue;
142 } else if selected.contains("Magenta") {
143 return Color::Magenta;
144 } else if selected.contains("Cyan") {
145 return Color::Cyan;
146 } else if selected.contains("White") {
147 return Color::White;
148 } else {
149 return Color::Red;
150 }
151}