use crate::cursor::Cursor;
use crate::ui;
use crate::RT;
use bogobble::{partial::ranger::Ranger, traits::*};
use std::fmt::Write;
use std::io::Write as IWrite;
use std::path::PathBuf;
use termion::color;
#[derive(Debug, Clone)]
pub struct Prompt {
pr_line: String,
built: String,
restore: Option<Cursor>,
pub options: Option<(Ranger, Vec<String>)>,
pub message: Option<String>,
pub cursor: Cursor,
}
impl Prompt {
pub fn new(pr_line: String) -> Self {
Prompt {
pr_line,
options: None,
message: None,
restore: None,
built: String::new(),
cursor: Cursor::at_end(String::new()),
}
}
pub fn esc(&mut self, rt: &mut RT) {
self.unprint(rt);
self.clear_help();
self.restore = None;
self.print(rt);
}
pub fn replace_line(&mut self, line: Option<&String>) {
self.clear_help();
let new_cursor = line.map(|l| Cursor::at_end(l.clone()));
match (&mut self.restore, new_cursor) {
(Some(_), Some(nc)) => self.cursor = nc,
(None, Some(mut nc)) => {
std::mem::swap(&mut nc, &mut self.cursor);
self.restore = Some(nc);
}
(Some(ref mut v), None) => {
std::mem::swap(&mut self.cursor, v);
self.restore = None;
}
_ => {} }
}
pub fn clear_help(&mut self) {
self.options = None;
self.message = None;
}
pub fn reset(&mut self, pr_line: String, rt: &mut RT) {
*self = Self::new(pr_line);
self.print(rt);
}
pub fn print(&mut self, rt: &mut RT) {
let pass1 = self.build(&self.cursor.s, true);
self.built = self.build(self.cursor.on_s(), false);
ui::print(&pass1);
ui::unprint(&pass1, rt, false);
ui::print(&self.built);
rt.flush().ok();
}
pub fn print_end(&mut self, rt: &mut RT) {
self.built = self.build(&self.cursor.s, false);
ui::print(&self.built);
rt.flush().ok();
}
pub fn unprint(&self, rt: &mut RT) {
ui::unprint(&self.built, rt, true);
}
pub fn build(&self, line: &str, with_ops: bool) -> String {
let mut res = String::new();
let (pwidth, _) = termion::terminal_size().unwrap_or((50, 50));
let line = build_line(line);
if let Some(m) = &self.message {
write!(res, "[{}]\n\r", m).ok();
}
res.push_str(&self.pr_line);
write!(res, "{}", line).ok();
if let (Some((_, ops)), true) = (&self.options, with_ops) {
match ops.len() {
n if n <= 10 => {
for (n, o) in ops.iter().enumerate() {
write!(res, "\n{}: {}", n, o).ok();
}
}
_ => {
for (n, o) in ops.iter().enumerate() {
let s = match PathBuf::from(o).file_name() {
Some(s) => s.to_string_lossy().to_string(),
None => o.to_string(),
};
let nl = match n % (pwidth as usize / 25) {
0 => "\n",
_ => "",
};
write!(res, "{}{:0>2}: {:20}", nl, n, s,).ok();
}
}
}
}
res
}
pub fn add_char(&mut self, c: char) {
if let Some((pos, mut ops)) = self.options.take() {
if let Some(n) = ui::char_as_int(c) {
if ops.len() <= 10 {
match ops.get(n) {
Some(v) => {
self.cursor.replace_range(pos, v);
self.clear_help();
}
None => {
self.message = Some("Selection Not Valid".to_string());
self.options = Some((pos, ops));
}
}
} else {
ops = ops.into_iter().skip(n * 10).take(10).collect();
self.options = Some((pos, ops))
}
return;
}
}
self.cursor.add_char(c);
self.clear_help();
}
pub fn del_char(&mut self) {
self.clear_help();
self.cursor.del_char();
}
pub fn do_print<F: Fn(&mut Prompt) -> T, T>(&mut self, rt: &mut RT, f: F) -> T {
self.unprint(rt);
let r = f(self);
self.print(rt);
r
}
pub fn do_cursor<F: Fn(&mut Cursor) -> T, T>(&mut self, rt: &mut RT, f: F) -> T {
self.unprint(rt);
let r = f(&mut self.cursor);
self.print(rt);
r
}
}
pub fn build_line<'a>(l: &str) -> String {
match crate::partial::Lines.parse_s(l) {
Ok(v) => {
let s = bogobble::partial::mark_list::mark_str(&v, l).expect("Marking out of String");
let res = format!("{}{}", s, color::Fg(color::Reset));
let res = res.replace("\n", "\n... ");
res
}
Err(e) => match e.index {
Some(0) | None => format!(
"{}{}{}",
color::Fg(color::LightRed),
l,
color::Fg(color::Reset),
)
.replace("\n", "\n... "),
Some(n) => format!(
"{}{}{}{}",
build_line(&l[0..n]),
color::Fg(color::LightRed),
&l[n..],
color::Fg(color::Reset)
)
.replace("\n", "\n..."),
},
}
}