use std::str;
use num_derive::ToPrimitive;
use num_traits::ToPrimitive;
use subprocess::{Popen, PopenConfig, Redirection};
use crate::errors::*;
#[derive(Debug, ToPrimitive, Clone)]
pub enum Location {
TopLeft = 1,
TopCentre = 2,
TopRight = 3,
MiddleLeft = 8,
MiddleCentre = 0,
MiddleRight = 4,
BottomLeft = 7,
BottomCentre = 6,
BottomRight = 5
}
#[derive(Debug, Clone)]
pub struct Dimensions {
pub width: i32,
pub height: i32,
pub lines: i32,
pub columns: i32
}
#[derive(Debug, Clone)]
pub struct Padding {
pub x: i32,
pub y: i32
}
#[derive(Debug, Clone)]
pub struct Window<'m> {
pub prompt: String,
pub message: Option<&'m str>,
pub additional_args: Vec<String>,
pub location: Location,
pub padding: Padding,
pub dimensions: Dimensions,
pub fullscreen: bool,
pub format: ReturnFormat
}
#[derive(Debug, Clone, PartialEq)]
pub enum ReturnFormat {
StringReturn,
IntReturn
}
impl<'a, 's, 'm> Window<'m> {
fn run_blocking(self, options: Vec<String>) -> Result<String, WindowError> {
let pc = PopenConfig {
stdout: Redirection::Pipe,
stdin: Redirection::Pipe,
..Default::default()
};
let options_arr = options
.iter()
.map(|s| s.replace("\n", ""))
.collect::<Vec<String>>()
.join("\n");
let mut call = vec!["rofi", "-dmenu", "-format"]
.iter()
.map(|s| s.to_string())
.collect::<Vec<String>>();
call.extend(self.to_args());
let mut p = Popen::create(&call, pc)?;
let (entry, _stdout) = p.communicate(Some(&options_arr))?;
let entry = entry.unwrap_or("-1".to_string());
match p.wait() {
Ok(_p) => Ok(entry.clone().trim().to_string()),
Err(e) => Err(e.into())
}
}
pub fn new(prompt: &'a str) -> Self {
Window {
prompt: prompt.to_owned(),
message: None,
additional_args: vec![],
location: Location::MiddleCentre,
padding: Padding { x: 0, y: 0 },
dimensions: Dimensions {
width: 0, height: 0, lines: 4,
columns: 1
},
fullscreen: false,
format: ReturnFormat::IntReturn
}
}
pub fn message(mut self, msg: &'static str) -> Self {
self.message = Some(msg);
self
}
pub fn location(mut self, l: Location) -> Self {
self.location = l;
self
}
pub fn padding(mut self, x: i32, y: i32) -> Self {
self.padding = Padding { x, y };
self
}
pub fn dimensions(mut self, d: Dimensions) -> Self {
self.dimensions = d;
self
}
pub fn prompt(mut self, s: String) -> Self {
self.prompt = s;
self
}
pub fn lines(mut self, l: i32) -> Self {
self.dimensions.lines = l;
self
}
pub fn fullscreen(mut self, f: bool) -> Self {
self.fullscreen = f;
self
}
pub fn format(mut self, f: char) -> Self {
match f {
's' => self.format = ReturnFormat::StringReturn,
'i' | _ => self.format = ReturnFormat::IntReturn
}
self
}
pub fn add_args(mut self, args: Vec<String>) -> Self {
self.additional_args.extend(args);
self
}
pub fn show(self, options: Vec<String>) -> Result<String, WindowError> {
let res = self.run_blocking(options);
match res {
Ok(d) => {
return Ok(d);
}
Err(e) => Err(e.into())
}
}
}
trait ToArgs {
fn to_args(&self) -> Vec<String>;
}
impl ToArgs for Dimensions {
fn to_args(&self) -> Vec<String> {
let mut args = Vec::new();
if self.width > 0 {
args.extend(vec!["-width".to_string(), self.width.to_string().clone()]);
}
if self.height > 0 {
args.extend(vec!["-height".to_string(), self.height.to_string().clone()]);
}
args.extend(vec![
"-lines".to_string(),
self.lines.to_string().clone(),
"-columns".to_string(),
self.columns.to_string().clone(),
]);
args
}
}
impl ToArgs for Padding {
fn to_args(&self) -> Vec<String> {
vec![
"-xoffset".to_string(),
self.x.to_string(),
"-yoffset".to_string(),
self.y.to_string(),
]
}
}
impl ToArgs for Location {
fn to_args(&self) -> Vec<String> {
vec![
"-location".to_string(),
ToPrimitive::to_u8(self).expect("k").to_string(),
]
}
}
impl ToArgs for ReturnFormat {
fn to_args(&self) -> Vec<String> {
match self {
ReturnFormat::StringReturn => vec!["s".to_string()],
ReturnFormat::IntReturn => vec!["i".to_string()]
}
}
}
impl<'a, 'm> ToArgs for Window<'m> {
fn to_args(&self) -> Vec<String> {
let mut args = Vec::new();
args.extend(self.format.to_args());
args.extend(self.dimensions.to_args());
if self.fullscreen {
args.extend(vec!["-fullscreen".to_string()]);
} else {
args.extend(self.padding.to_args());
args.extend(self.location.to_args());
}
if let Some(msg) = self.message {
args.extend(vec!["-mesg".to_string(), msg.to_string()]);
}
args.extend(vec!["-p".to_string(), self.prompt.clone()]);
args.extend(self.additional_args.clone());
args
}
}